Clover icon

compiler

  1. Project Clover database Mon Jan 2 2023 15:09:37 MST
  2. Package com.google.javascript.jscomp

File LooseTypeCheckTest.java

 

Code metrics

22
1,104
806
2
7,075
5,878
820
0.74
1.37
403
1.02

Classes

Class Line # Actions
LooseTypeCheckTest 47 1,102 819 14
0.9927423699.3%
LooseTypeCheckTest.TypeCheckResult 7066 2 1 0
1.0100%
 

Contributing tests

This file is covered by 2343 tests. .

Source view

1    /*
2    * Copyright 2006 The Closure Compiler Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.google.javascript.jscomp;
18   
19    import com.google.common.base.Joiner;
20    import com.google.common.collect.Lists;
21    import com.google.common.collect.Sets;
22    import com.google.javascript.jscomp.CheckLevel;
23    import com.google.javascript.jscomp.Scope.Var;
24    import com.google.javascript.jscomp.type.ClosureReverseAbstractInterpreter;
25    import com.google.javascript.jscomp.type.SemanticReverseAbstractInterpreter;
26    import com.google.javascript.rhino.InputId;
27    import com.google.javascript.rhino.Node;
28    import com.google.javascript.rhino.Token;
29    import com.google.javascript.rhino.jstype.FunctionType;
30    import com.google.javascript.rhino.jstype.JSType;
31    import com.google.javascript.rhino.jstype.JSTypeNative;
32    import com.google.javascript.rhino.jstype.ObjectType;
33    import com.google.javascript.rhino.testing.Asserts;
34   
35    import java.util.Arrays;
36    import java.util.List;
37    import java.util.Set;
38   
39    /**
40    * Tests {@link TypeCheck}.
41    *
42    * This is a temporary fork of the TypeCheckTest for the experimental
43    * "looseTypes" option. These tests should be be folded into TypeCheckTest
44    * or removed along with the looseTypes option.
45    *
46    */
 
47    public class LooseTypeCheckTest extends CompilerTypeTestCase {
48   
 
49  2343 toggle @Override
50    public CompilerOptions getOptions() {
51  2343 CompilerOptions options = super.getOptions();
52  2343 options.looseTypes = true;
53  2343 return options;
54    }
55   
 
56  3 toggle public void testInitialTypingScope() {
57  3 Scope s = new TypedScopeCreator(compiler,
58    CodingConventions.getDefault()).createInitialScope(
59    new Node(Token.BLOCK));
60   
61  3 assertTypeEquals(ARRAY_FUNCTION_TYPE, s.getVar("Array").getType());
62  3 assertTypeEquals(BOOLEAN_OBJECT_FUNCTION_TYPE,
63    s.getVar("Boolean").getType());
64  3 assertTypeEquals(DATE_FUNCTION_TYPE, s.getVar("Date").getType());
65  3 assertTypeEquals(ERROR_FUNCTION_TYPE, s.getVar("Error").getType());
66  3 assertTypeEquals(EVAL_ERROR_FUNCTION_TYPE,
67    s.getVar("EvalError").getType());
68  3 assertTypeEquals(NUMBER_OBJECT_FUNCTION_TYPE,
69    s.getVar("Number").getType());
70  3 assertTypeEquals(OBJECT_FUNCTION_TYPE, s.getVar("Object").getType());
71  3 assertTypeEquals(RANGE_ERROR_FUNCTION_TYPE,
72    s.getVar("RangeError").getType());
73  3 assertTypeEquals(REFERENCE_ERROR_FUNCTION_TYPE,
74    s.getVar("ReferenceError").getType());
75  3 assertTypeEquals(REGEXP_FUNCTION_TYPE, s.getVar("RegExp").getType());
76  3 assertTypeEquals(STRING_OBJECT_FUNCTION_TYPE,
77    s.getVar("String").getType());
78  3 assertTypeEquals(SYNTAX_ERROR_FUNCTION_TYPE,
79    s.getVar("SyntaxError").getType());
80  3 assertTypeEquals(TYPE_ERROR_FUNCTION_TYPE,
81    s.getVar("TypeError").getType());
82  3 assertTypeEquals(URI_ERROR_FUNCTION_TYPE,
83    s.getVar("URIError").getType());
84    }
85   
 
86  3 toggle public void testTypeCheck1() throws Exception {
87  3 testTypes("/**@return {void}*/function foo(){ if (foo()) return; }");
88    }
89   
 
90  3 toggle public void testTypeCheck2() throws Exception {
91  3 testTypes("/**@return {void}*/function foo(){ var x=foo(); x--; }",
92    "increment/decrement\n" +
93    "found : undefined\n" +
94    "required: number");
95    }
96   
 
97  3 toggle public void testTypeCheck4() throws Exception {
98  3 testTypes("/**@return {void}*/function foo(){ !foo(); }");
99    }
100   
 
101  3 toggle public void testTypeCheck5() throws Exception {
102  3 testTypes("/**@return {void}*/function foo(){ var a = +foo(); }",
103    "sign operator\n" +
104    "found : undefined\n" +
105    "required: number");
106    }
107   
 
108  3 toggle public void testTypeCheck6() throws Exception {
109  3 testTypes(
110    "/**@return {void}*/function foo(){" +
111    "/** @type {undefined|number} */var a;if (a == foo())return;}");
112    }
113   
 
114  3 toggle public void testTypeCheck8() throws Exception {
115  3 testTypes("/**@return {void}*/function foo(){do {} while (foo());}");
116    }
117   
 
118  3 toggle public void testTypeCheck9() throws Exception {
119  3 testTypes("/**@return {void}*/function foo(){while (foo());}");
120    }
121   
 
122  3 toggle public void testTypeCheck10() throws Exception {
123  3 testTypes("/**@return {void}*/function foo(){for (;foo(););}");
124    }
125   
 
126  3 toggle public void testTypeCheck11() throws Exception {
127  3 testTypes("/**@type !Number */var a;" +
128    "/**@type !String */var b;" +
129    "a = b;",
130    "assignment\n" +
131    "found : String\n" +
132    "required: Number");
133    }
134   
 
135  3 toggle public void testTypeCheck12() throws Exception {
136  3 testTypes("/**@return {!Object}*/function foo(){var a = 3^foo();}",
137    "bad right operand to bitwise operator\n" +
138    "found : Object\n" +
139    "required: (boolean|null|number|string|undefined)");
140    }
141   
 
142  3 toggle public void testTypeCheck13() throws Exception {
143  3 testTypes("/**@type {!Number|!String}*/var i; i=/xx/;",
144    "assignment\n" +
145    "found : RegExp\n" +
146    "required: (Number|String)");
147    }
148   
 
149  3 toggle public void testTypeCheck14() throws Exception {
150  3 testTypes("/**@param opt_a*/function foo(opt_a){}");
151    }
152   
153   
 
154  3 toggle public void testTypeCheck15() throws Exception {
155  3 testTypes("/**@type {Number} */var x;x=null;x=10;",
156    "assignment\n" +
157    "found : number\n" +
158    "required: (Number|null|undefined)");
159    }
160   
 
161  3 toggle public void testTypeCheck16a() throws Exception {
162  3 testTypes("/**@type {Number|null} */var x='';",
163    "initializing variable\n" +
164    "found : string\n" +
165    "required: (Number|null|undefined)");
166    }
167   
 
168  3 toggle public void testTypeCheck16b() throws Exception {
169  3 testTypes("/**@type {!Number|null} */var x='';",
170    "initializing variable\n" +
171    "found : string\n" +
172    "required: (Number|null)");
173    }
174   
 
175  3 toggle public void testTypeCheck17() throws Exception {
176  3 testTypes("/**@return {Number}\n@param {Number} opt_foo */\n" +
177    "function a(opt_foo){\nreturn /**@type {Number}*/(opt_foo);\n}");
178    }
179   
180   
 
181  3 toggle public void testTypeCheck18() throws Exception {
182  3 testTypes("/**@return {RegExp}\n*/\n function a(){return new RegExp();}");
183    }
184   
 
185  3 toggle public void testTypeCheck19() throws Exception {
186  3 testTypes("/**@return {Array}\n*/\n function a(){return new Array();}");
187    }
188   
 
189  3 toggle public void testTypeCheck20() throws Exception {
190  3 testTypes("/**@return {Date}\n*/\n function a(){return new Date();}");
191    }
192   
 
193  3 toggle public void testTypeCheckBasicDowncast() throws Exception {
194  3 testTypes("/** @constructor */function foo() {}\n" +
195    "/** @type {Object} */ var bar = new foo();\n");
196    }
197   
 
198  3 toggle public void testTypeCheckNoDowncastToNumber() throws Exception {
199  3 testTypes("/** @constructor */function foo() {}\n" +
200    "/** @type {!Number} */ var bar = new foo();\n",
201    "initializing variable\n" +
202    "found : foo\n" +
203    "required: Number");
204    }
205   
 
206  3 toggle public void testTypeCheck21() throws Exception {
207  3 testTypes("/** @type Array.<String> */var foo;");
208    }
209   
 
210  3 toggle public void testTypeCheck22() throws Exception {
211  3 testTypes("/** @param {Element|Object} p */\nfunction foo(p){}\n" +
212    "/** @constructor */function Element(){}\n" +
213    "/** @type {Element|Object} */var v;\n" +
214    "foo(v);\n");
215    }
216   
 
217  3 toggle public void testTypeCheck23() throws Exception {
218  3 testTypes("/** @type {(Object,Null)} */var foo; foo = null;");
219    }
220   
 
221  3 toggle public void testTypeCheck24() throws Exception {
222  3 testTypes("/** @constructor */function MyType(){}\n" +
223    "/** @type {(MyType,Null)} */var foo; foo = null;");
224    }
225   
 
226  3 toggle public void testTypeCheckDefaultExterns() throws Exception {
227  3 testTypes("/** @param {string} x */ function f(x) {}" +
228    "f([].length);" ,
229    "actual parameter 1 of f does not match formal parameter\n" +
230    "found : number\n" +
231    "required: string");
232    }
233   
 
234  3 toggle public void testTypeCheckCustomExterns() throws Exception {
235  3 testTypes(
236    DEFAULT_EXTERNS + "/** @type {boolean} */ Array.prototype.oogabooga;",
237    "/** @param {string} x */ function f(x) {}" +
238    "f([].oogabooga);" ,
239    "actual parameter 1 of f does not match formal parameter\n" +
240    "found : boolean\n" +
241    "required: string", false);
242    }
243   
 
244  3 toggle public void testParameterizedArray1() throws Exception {
245  3 testTypes("/** @param {!Array.<number>} a\n" +
246    "* @return {string}\n" +
247    "*/ var f = function(a) { return a[0]; };",
248    "inconsistent return type\n" +
249    "found : number\n" +
250    "required: string");
251    }
252   
 
253  3 toggle public void testParameterizedArray2() throws Exception {
254  3 testTypes("/** @param {!Array.<!Array.<number>>} a\n" +
255    "* @return {number}\n" +
256    "*/ var f = function(a) { return a[0]; };",
257    "inconsistent return type\n" +
258    "found : Array.<number>\n" +
259    "required: number");
260    }
261   
 
262  3 toggle public void testParameterizedArray3() throws Exception {
263  3 testTypes("/** @param {!Array.<number>} a\n" +
264    "* @return {number}\n" +
265    "*/ var f = function(a) { a[1] = 0; return a[0]; };");
266    }
267   
 
268  3 toggle public void testParameterizedArray4() throws Exception {
269  3 testTypes("/** @param {!Array.<number>} a\n" +
270    "*/ var f = function(a) { a[0] = 'a'; };",
271    "assignment\n" +
272    "found : string\n" +
273    "required: number");
274    }
275   
 
276  3 toggle public void testParameterizedArray5() throws Exception {
277  3 testTypes("/** @param {!Array.<*>} a\n" +
278    "*/ var f = function(a) { a[0] = 'a'; };");
279    }
280   
 
281  3 toggle public void testParameterizedArray6() throws Exception {
282  3 testTypes("/** @param {!Array.<*>} a\n" +
283    "* @return {string}\n" +
284    "*/ var f = function(a) { return a[0]; };",
285    "inconsistent return type\n" +
286    "found : *\n" +
287    "required: string");
288    }
289   
 
290  3 toggle public void testParameterizedArray7() throws Exception {
291  3 testTypes("/** @param {?Array.<number>} a\n" +
292    "* @return {string}\n" +
293    "*/ var f = function(a) { return a[0]; };",
294    "inconsistent return type\n" +
295    "found : number\n" +
296    "required: string");
297    }
298   
 
299  3 toggle public void testParameterizedObject1() throws Exception {
300  3 testTypes("/** @param {!Object.<number>} a\n" +
301    "* @return {string}\n" +
302    "*/ var f = function(a) { return a[0]; };",
303    "inconsistent return type\n" +
304    "found : number\n" +
305    "required: string");
306    }
307   
 
308  3 toggle public void testParameterizedObject2() throws Exception {
309  3 testTypes("/** @param {!Object.<string,number>} a\n" +
310    "* @return {string}\n" +
311    "*/ var f = function(a) { return a['x']; };",
312    "inconsistent return type\n" +
313    "found : number\n" +
314    "required: string");
315    }
316   
 
317  3 toggle public void testParameterizedObject3() throws Exception {
318  3 testTypes("/** @param {!Object.<number,string>} a\n" +
319    "* @return {string}\n" +
320    "*/ var f = function(a) { return a['x']; };",
321    "restricted index type\n" +
322    "found : string\n" +
323    "required: number");
324    }
325   
 
326  3 toggle public void testParameterizedObject4() throws Exception {
327  3 testTypes("/** @enum {string} */ var E = {A: 'a', B: 'b'};\n" +
328    "/** @param {!Object.<E,string>} a\n" +
329    "* @return {string}\n" +
330    "*/ var f = function(a) { return a['x']; };",
331    "restricted index type\n" +
332    "found : string\n" +
333    "required: E.<string>");
334    }
335   
 
336  3 toggle public void testUnionOfFunctionAndType() throws Exception {
337  3 testTypes("/** @type {null|(function(Number):void)} */ var a;" +
338    "/** @type {(function(Number):void)|null} */ var b = null; a = b;");
339    }
340   
 
341  3 toggle public void testOptionalParameterComparedToUndefined() throws Exception {
342  3 testTypes("/**@param opt_a {Number}*/function foo(opt_a)" +
343    "{if (opt_a==undefined) var b = 3;}");
344    }
345   
 
346  3 toggle public void testOptionalAllType() throws Exception {
347  3 testTypes("/** @param {*} opt_x */function f(opt_x) { return opt_x }\n" +
348    "/** @type {*} */var y;\n" +
349    "f(y);");
350    }
351   
 
352  3 toggle public void testOptionalUnknownNamedType() throws Exception {
353  3 testTypes("/** @param {!T} opt_x\n@return {undefined} */\n" +
354    "function f(opt_x) { return opt_x; }\n" +
355    "/** @constructor */var T = function() {};",
356    "inconsistent return type\n" +
357    "found : (T|undefined)\n" +
358    "required: undefined");
359    }
360   
 
361  3 toggle public void testOptionalArgFunctionParam() throws Exception {
362  3 testTypes("/** @param {function(number=)} a */" +
363    "function f(a) {a()};");
364    }
365   
 
366  3 toggle public void testOptionalArgFunctionParam2() throws Exception {
367  3 testTypes("/** @param {function(number=)} a */" +
368    "function f(a) {a(3)};");
369    }
370   
 
371  3 toggle public void testOptionalArgFunctionParam3() throws Exception {
372  3 testTypes("/** @param {function(number=)} a */" +
373    "function f(a) {a(undefined)};");
374    }
375   
 
376  3 toggle public void testOptionalArgFunctionParam4() throws Exception {
377  3 String expectedWarning = "Function a: called with 2 argument(s). " +
378    "Function requires at least 0 argument(s) and no more than 1 " +
379    "argument(s).";
380   
381  3 testTypes("/** @param {function(number=)} a */function f(a) {a(3,4)};",
382    expectedWarning, false);
383    }
384   
 
385  3 toggle public void testOptionalArgFunctionParamError() throws Exception {
386  3 String expectedWarning =
387    "Bad type annotation. variable length argument must be last";
388  3 testTypes("/** @param {function(...[number], number=)} a */" +
389    "function f(a) {};", expectedWarning, false);
390    }
391   
 
392  3 toggle public void testOptionalNullableArgFunctionParam() throws Exception {
393  3 testTypes("/** @param {function(?number=)} a */" +
394    "function f(a) {a()};");
395    }
396   
 
397  3 toggle public void testOptionalNullableArgFunctionParam2() throws Exception {
398  3 testTypes("/** @param {function(?number=)} a */" +
399    "function f(a) {a(null)};");
400    }
401   
 
402  3 toggle public void testOptionalNullableArgFunctionParam3() throws Exception {
403  3 testTypes("/** @param {function(?number=)} a */" +
404    "function f(a) {a(3)};");
405    }
406   
 
407  3 toggle public void testOptionalArgFunctionReturn() throws Exception {
408  3 testTypes("/** @return {function(number=)} */" +
409    "function f() { return function(opt_x) { }; };" +
410    "f()()");
411    }
412   
 
413  3 toggle public void testOptionalArgFunctionReturn2() throws Exception {
414  3 testTypes("/** @return {function(Object=)} */" +
415    "function f() { return function(opt_x) { }; };" +
416    "f()({})");
417    }
418   
 
419  3 toggle public void testBooleanType() throws Exception {
420  3 testTypes("/**@type {boolean} */var x = 1 < 2;");
421    }
422   
 
423  3 toggle public void testBooleanReduction1() throws Exception {
424  3 testTypes("/**@type {string} */var x; x = null || \"a\";");
425    }
426   
 
427  3 toggle public void testBooleanReduction2() throws Exception {
428    // It's important for the type system to recognize that in no case
429    // can the boolean expression evaluate to a boolean value.
430  3 testTypes("/** @param {string} s\n @return {string} */" +
431    "(function(s) { return ((s == 'a') && s) || 'b'; })");
432    }
433   
 
434  3 toggle public void testBooleanReduction3() throws Exception {
435  3 testTypes("/** @param {string} s\n @return {string?} */" +
436    "(function(s) { return s && null && 3; })");
437    }
438   
 
439  3 toggle public void testBooleanReduction4() throws Exception {
440  3 testTypes("/** @param {Object} x\n @return {Object} */" +
441    "(function(x) { return null || x || null ; })");
442    }
443   
 
444  3 toggle public void testBooleanReduction5() throws Exception {
445  3 testTypes("/**\n" +
446    "* @param {Array|string} x\n" +
447    "* @return {string?}\n" +
448    "*/\n" +
449    "var f = function(x) {\n" +
450    "if (!x || typeof x == 'string') {\n" +
451    "return x;\n" +
452    "}\n" +
453    "return null;\n" +
454    "};");
455    }
456   
 
457  3 toggle public void testBooleanReduction6() throws Exception {
458  3 testTypes("/**\n" +
459    "* @param {Array|string|null} x\n" +
460    "* @return {string?}\n" +
461    "*/\n" +
462    "var f = function(x) {\n" +
463    "if (!(x && typeof x != 'string')) {\n" +
464    "return x;\n" +
465    "}\n" +
466    "return null;\n" +
467    "};");
468    }
469   
 
470  3 toggle public void testBooleanReduction7() throws Exception {
471  3 testTypes("/** @constructor */var T = function() {};\n" +
472    "/**\n" +
473    "* @param {Array|T} x\n" +
474    "* @return {null|undefined}\n" +
475    "*/\n" +
476    "var f = function(x) {\n" +
477    "if (!x) {\n" +
478    "return x;\n" +
479    "}\n" +
480    "return null;\n" +
481    "};");
482    }
483   
 
484  3 toggle public void testNullAnd() throws Exception {
485  3 testTypes("/** @type null */var x;\n" +
486    "/** @type number */var r = x && x;",
487    "initializing variable\n" +
488    "found : null\n" +
489    "required: number");
490    }
491   
 
492  3 toggle public void testNullOr() throws Exception {
493  3 testTypes("/** @type null */var x;\n" +
494    "/** @type number */var r = x || x;",
495    "initializing variable\n" +
496    "found : null\n" +
497    "required: number");
498    }
499   
 
500  3 toggle public void testBooleanPreservation1() throws Exception {
501  3 testTypes("/**@type {string} */var x = \"a\";" +
502    "x = ((x == \"a\") && x) || x == \"b\";",
503    "assignment\n" +
504    "found : (boolean|string)\n" +
505    "required: string");
506    }
507   
 
508  3 toggle public void testBooleanPreservation2() throws Exception {
509  3 testTypes("/**@type {string} */var x = \"a\"; x = (x == \"a\") || x;",
510    "assignment\n" +
511    "found : (boolean|string)\n" +
512    "required: string");
513    }
514   
 
515  3 toggle public void testBooleanPreservation3() throws Exception {
516  3 testTypes("/** @param {Function?} x\n @return {boolean?} */" +
517    "function f(x) { return x && x == \"a\"; }",
518    "condition always evaluates to false\n" +
519    "left : Function\n" +
520    "right: string");
521    }
522   
 
523  3 toggle public void testBooleanPreservation4() throws Exception {
524  3 testTypes("/** @param {Function?|boolean} x\n @return {boolean} */" +
525    "function f(x) { return x && x == \"a\"; }",
526    "inconsistent return type\n" +
527    "found : (boolean|null|undefined)\n" +
528    "required: boolean");
529    }
530   
 
531  3 toggle public void testTypeOfReduction1() throws Exception {
532  3 testTypes("/** @param {string|number} x\n @return {string} */ " +
533    "function f(x) { return typeof x == 'number' ? String(x) : x; }");
534    }
535   
 
536  3 toggle public void testTypeOfReduction2() throws Exception {
537  3 testTypes("/** @param {string|number} x\n @return {string} */ " +
538    "function f(x) { return typeof x != 'string' ? String(x) : x; }");
539    }
540   
 
541  3 toggle public void testTypeOfReduction3() throws Exception {
542  3 testTypes("/** @param {number|null} x\n @return {number} */ " +
543    "function f(x) { return typeof x == 'object' ? 1 : x; }");
544    }
545   
 
546  3 toggle public void testTypeOfReduction4() throws Exception {
547  3 testTypes("/** @param {Object|undefined} x\n @return {Object} */ " +
548    "function f(x) { return typeof x == 'undefined' ? {} : x; }");
549    }
550   
 
551  3 toggle public void testTypeOfReduction5() throws Exception {
552  3 testTypes("/** @enum {string} */ var E = {A: 'a', B: 'b'};\n" +
553    "/** @param {!E|number} x\n @return {string} */ " +
554    "function f(x) { return typeof x != 'number' ? x : 'a'; }");
555    }
556   
 
557  3 toggle public void testTypeOfReduction6() throws Exception {
558  3 testTypes("/** @param {number|string} x\n@return {string} */\n" +
559    "function f(x) {\n" +
560    "return typeof x == 'string' && x.length == 3 ? x : 'a';\n" +
561    "}");
562    }
563   
 
564  3 toggle public void testTypeOfReduction7() throws Exception {
565  3 testTypes("/** @return {string} */var f = function(x) { " +
566    "return typeof x == 'number' ? x : 'a'; }",
567    "inconsistent return type\n" +
568    "found : (number|string)\n" +
569    "required: string");
570    }
571   
 
572  3 toggle public void testTypeOfReduction8() throws Exception {
573  3 testClosureTypes(
574    CLOSURE_DEFS +
575    "/** @param {number|string} x\n@return {string} */\n" +
576    "function f(x) {\n" +
577    "return goog.isString(x) && x.length == 3 ? x : 'a';\n" +
578    "}", null);
579    }
580   
 
581  3 toggle public void testTypeOfReduction9() throws Exception {
582  3 testClosureTypes(
583    CLOSURE_DEFS +
584    "/** @param {!Array|string} x\n@return {string} */\n" +
585    "function f(x) {\n" +
586    "return goog.isArray(x) ? 'a' : x;\n" +
587    "}", null);
588    }
589   
 
590  3 toggle public void testTypeOfReduction10() throws Exception {
591  3 testClosureTypes(
592    CLOSURE_DEFS +
593    "/** @param {Array|string} x\n@return {Array} */\n" +
594    "function f(x) {\n" +
595    "return goog.isArray(x) ? x : [];\n" +
596    "}", null);
597    }
598   
 
599  3 toggle public void testTypeOfReduction11() throws Exception {
600  3 testClosureTypes(
601    CLOSURE_DEFS +
602    "/** @param {Array|string} x\n@return {Array} */\n" +
603    "function f(x) {\n" +
604    "return goog.isObject(x) ? x : [];\n" +
605    "}", null);
606    }
607   
 
608  3 toggle public void testTypeOfReduction12() throws Exception {
609  3 testTypes("/** @enum {string} */ var E = {A: 'a', B: 'b'};\n" +
610    "/** @param {E|Array} x\n @return {Array} */ " +
611    "function f(x) { return typeof x == 'object' ? x : []; }");
612    }
613   
 
614  3 toggle public void testTypeOfReduction13() throws Exception {
615  3 testClosureTypes(
616    CLOSURE_DEFS +
617    "/** @enum {string} */ var E = {A: 'a', B: 'b'};\n" +
618    "/** @param {E|Array} x\n@return {Array} */ " +
619    "function f(x) { return goog.isObject(x) ? x : []; }", null);
620    }
621   
 
622  3 toggle public void testTypeOfReduction14() throws Exception {
623    // Don't do type inference on GETELEMs.
624  3 testClosureTypes(
625    CLOSURE_DEFS +
626    "function f(x) { " +
627    " return goog.isString(arguments[0]) ? arguments[0] : 0;" +
628    "}", null);
629    }
630   
 
631  3 toggle public void testTypeOfReduction15() throws Exception {
632    // Don't do type inference on GETELEMs.
633  3 testClosureTypes(
634    CLOSURE_DEFS +
635    "function f(x) { " +
636    " return typeof arguments[0] == 'string' ? arguments[0] : 0;" +
637    "}", null);
638    }
639   
 
640  3 toggle public void testQualifiedNameReduction1() throws Exception {
641  3 testTypes("var x = {}; /** @type {string?} */ x.a = 'a';\n" +
642    "/** @return {string} */ var f = function() {\n" +
643    "return x.a ? x.a : 'a'; }");
644    }
645   
 
646  3 toggle public void testQualifiedNameReduction2() throws Exception {
647  3 testTypes("/** @param {string?} a\n@constructor */ var T = " +
648    "function(a) {this.a = a};\n" +
649    "/** @return {string} */ T.prototype.f = function() {\n" +
650    "return this.a ? this.a : 'a'; }");
651    }
652   
 
653  3 toggle public void testQualifiedNameReduction3() throws Exception {
654  3 testTypes("/** @param {string|Array} a\n@constructor */ var T = " +
655    "function(a) {this.a = a};\n" +
656    "/** @return {string} */ T.prototype.f = function() {\n" +
657    "return typeof this.a == 'string' ? this.a : 'a'; }");
658    }
659   
 
660  3 toggle public void testQualifiedNameReduction4() throws Exception {
661  3 testClosureTypes(
662    CLOSURE_DEFS +
663    "/** @param {string|Array} a\n@constructor */ var T = " +
664    "function(a) {this.a = a};\n" +
665    "/** @return {string} */ T.prototype.f = function() {\n" +
666    "return goog.isString(this.a) ? this.a : 'a'; }", null);
667    }
668   
 
669  3 toggle public void testInstanceOfReduction1() throws Exception {
670  3 testTypes("/** @constructor */ var T = function() {};\n" +
671    "/** @param {T|string} x\n@return {T} */\n" +
672    "var f = function(x) {\n" +
673    "if (x instanceof T) { return x; } else { return new T(); }\n" +
674    "};");
675    }
676   
 
677  3 toggle public void testInstanceOfReduction2() throws Exception {
678  3 testTypes("/** @constructor */ var T = function() {};\n" +
679    "/** @param {!T|string} x\n@return {string} */\n" +
680    "var f = function(x) {\n" +
681    "if (x instanceof T) { return ''; } else { return x; }\n" +
682    "};");
683    }
684   
 
685  3 toggle public void testPropertyInferredPropagation() throws Exception {
686  3 testTypes("/** @return {Object} */function f() { return {}; }\n" +
687    "function g() { var x = f(); if (x.p) x.a = 'a'; else x.a = 'b'; }\n" +
688    "function h() { var x = f(); x.a = false; }");
689    }
690   
 
691  3 toggle public void testPropertyInference1() throws Exception {
692  3 testTypes(
693    "/** @constructor */ function F() { this.x_ = true; }" +
694    "/** @return {string} */" +
695    "F.prototype.bar = function() { if (this.x_) return this.x_; };",
696    "inconsistent return type\n" +
697    "found : boolean\n" +
698    "required: string");
699    }
700   
 
701  3 toggle public void testPropertyInference2() throws Exception {
702  3 testTypes(
703    "/** @constructor */ function F() { this.x_ = true; }" +
704    "F.prototype.baz = function() { this.x_ = null; };" +
705    "/** @return {string} */" +
706    "F.prototype.bar = function() { if (this.x_) return this.x_; };",
707    "inconsistent return type\n" +
708    "found : boolean\n" +
709    "required: string");
710    }
711   
 
712  3 toggle public void testPropertyInference3() throws Exception {
713  3 testTypes(
714    "/** @constructor */ function F() { this.x_ = true; }" +
715    "F.prototype.baz = function() { this.x_ = 3; };" +
716    "/** @return {string} */" +
717    "F.prototype.bar = function() { if (this.x_) return this.x_; };",
718    "inconsistent return type\n" +
719    "found : (boolean|number)\n" +
720    "required: string");
721    }
722   
 
723  3 toggle public void testPropertyInference4() throws Exception {
724  3 testTypes(
725    "/** @constructor */ function F() { }" +
726    "F.prototype.x_ = 3;" +
727    "/** @return {string} */" +
728    "F.prototype.bar = function() { if (this.x_) return this.x_; };",
729    "inconsistent return type\n" +
730    "found : number\n" +
731    "required: string");
732    }
733   
 
734  3 toggle public void testPropertyInference5() throws Exception {
735  3 testTypes(
736    "/** @constructor */ function F() { }" +
737    "F.prototype.baz = function() { this.x_ = 3; };" +
738    "/** @return {string} */" +
739    "F.prototype.bar = function() { if (this.x_) return this.x_; };");
740    }
741   
 
742  3 toggle public void testPropertyInference6() throws Exception {
743  3 testTypes(
744    "/** @constructor */ function F() { }" +
745    "(new F).x_ = 3;" +
746    "/** @return {string} */" +
747    "F.prototype.bar = function() { return this.x_; };");
748    }
749   
 
750  3 toggle public void testPropertyInference7() throws Exception {
751  3 testTypes(
752    "/** @constructor */ function F() { this.x_ = true; }" +
753    "(new F).x_ = 3;" +
754    "/** @return {string} */" +
755    "F.prototype.bar = function() { return this.x_; };",
756    "inconsistent return type\n" +
757    "found : boolean\n" +
758    "required: string");
759    }
760   
 
761  3 toggle public void testPropertyInference8() throws Exception {
762  3 testTypes(
763    "/** @constructor */ function F() { " +
764    " /** @type {string} */ this.x_ = 'x';" +
765    "}" +
766    "(new F).x_ = 3;" +
767    "/** @return {string} */" +
768    "F.prototype.bar = function() { return this.x_; };",
769    "assignment to property x_ of F\n" +
770    "found : number\n" +
771    "required: string");
772    }
773   
 
774  3 toggle public void testNoPersistentTypeInferenceForObjectProperties()
775    throws Exception {
776  3 testTypes("/** @param {Object} o\n@param {string} x */\n" +
777    "function s1(o,x) { o.x = x; }\n" +
778    "/** @param {Object} o\n@return {string} */\n" +
779    "function g1(o) { return typeof o.x == 'undefined' ? '' : o.x; }\n" +
780    "/** @param {Object} o\n@param {number} x */\n" +
781    "function s2(o,x) { o.x = x; }\n" +
782    "/** @param {Object} o\n@return {number} */\n" +
783    "function g2(o) { return typeof o.x == 'undefined' ? 0 : o.x; }");
784    }
785   
 
786  3 toggle public void testNoPersistentTypeInferenceForFunctionProperties()
787    throws Exception {
788  3 testTypes("/** @param {Function} o\n@param {string} x */\n" +
789    "function s1(o,x) { o.x = x; }\n" +
790    "/** @param {Function} o\n@return {string} */\n" +
791    "function g1(o) { return typeof o.x == 'undefined' ? '' : o.x; }\n" +
792    "/** @param {Function} o\n@param {number} x */\n" +
793    "function s2(o,x) { o.x = x; }\n" +
794    "/** @param {Function} o\n@return {number} */\n" +
795    "function g2(o) { return typeof o.x == 'undefined' ? 0 : o.x; }");
796    }
797   
 
798  3 toggle public void testObjectPropertyTypeInferredInLocalScope1() throws Exception {
799  3 testTypes("/** @param {!Object} o\n@return {string} */\n" +
800    "function f(o) { o.x = 1; return o.x; }",
801    "inconsistent return type\n" +
802    "found : number\n" +
803    "required: string");
804    }
805   
 
806  3 toggle public void testObjectPropertyTypeInferredInLocalScope2() throws Exception {
807  3 testTypes("/**@param {!Object} o\n@param {number?} x\n@return {string}*/" +
808    "function f(o, x) { o.x = 'a';\nif (x) {o.x = x;}\nreturn o.x; }",
809    "inconsistent return type\n" +
810    "found : (number|string)\n" +
811    "required: string");
812    }
813   
 
814  3 toggle public void testObjectPropertyTypeInferredInLocalScope3() throws Exception {
815  3 testTypes("/**@param {!Object} o\n@param {number?} x\n@return {string}*/" +
816    "function f(o, x) { if (x) {o.x = x;} else {o.x = 'a';}\nreturn o.x; }",
817    "inconsistent return type\n" +
818    "found : (number|string)\n" +
819    "required: string");
820    }
821   
 
822  3 toggle public void testMismatchingOverridingInferredPropertyBeforeDeclaredProperty1()
823    throws Exception {
824  3 testTypes("/** @constructor */var T = function() { this.x = ''; };\n" +
825    "/** @type {number} */ T.prototype.x = 0;",
826    "assignment to property x of T\n" +
827    "found : string\n" +
828    "required: number");
829    }
830   
 
831  3 toggle public void testMismatchingOverridingInferredPropertyBeforeDeclaredProperty2()
832    throws Exception {
833  3 testTypes("/** @constructor */var T = function() { this.x = ''; };\n" +
834    "/** @type {number} */ T.prototype.x;",
835    "assignment to property x of T\n" +
836    "found : string\n" +
837    "required: number");
838    }
839   
 
840  3 toggle public void testMismatchingOverridingInferredPropertyBeforeDeclaredProperty3()
841    throws Exception {
842  3 testTypes("/** @type {Object} */ var n = {};\n" +
843    "/** @constructor */ n.T = function() { this.x = ''; };\n" +
844    "/** @type {number} */ n.T.prototype.x = 0;",
845    "assignment to property x of n.T\n" +
846    "found : string\n" +
847    "required: number");
848    }
849   
 
850  3 toggle public void testMismatchingOverridingInferredPropertyBeforeDeclaredProperty4()
851    throws Exception {
852  3 testTypes("var n = {};\n" +
853    "/** @constructor */ n.T = function() { this.x = ''; };\n" +
854    "/** @type {number} */ n.T.prototype.x = 0;",
855    "assignment to property x of n.T\n" +
856    "found : string\n" +
857    "required: number");
858    }
859   
 
860  3 toggle public void testPropertyUsedBeforeDefinition1() throws Exception {
861  3 testTypes("/** @constructor */ var T = function() {};\n" +
862    "/** @return {string} */" +
863    "T.prototype.f = function() { return this.g(); };\n" +
864    "/** @return {number} */ T.prototype.g = function() { return 1; };\n",
865    "inconsistent return type\n" +
866    "found : number\n" +
867    "required: string");
868    }
869   
 
870  3 toggle public void testPropertyUsedBeforeDefinition2() throws Exception {
871  3 testTypes("var n = {};\n" +
872    "/** @constructor */ n.T = function() {};\n" +
873    "/** @return {string} */" +
874    "n.T.prototype.f = function() { return this.g(); };\n" +
875    "/** @return {number} */ n.T.prototype.g = function() { return 1; };\n",
876    "inconsistent return type\n" +
877    "found : number\n" +
878    "required: string");
879    }
880   
 
881  3 toggle public void testAdd1() throws Exception {
882  3 testTypes("/**@return {void}*/function foo(){var a = 'abc'+foo();}");
883    }
884   
 
885  3 toggle public void testAdd2() throws Exception {
886  3 testTypes("/**@return {void}*/function foo(){var a = foo()+4;}");
887    }
888   
 
889  3 toggle public void testAdd3() throws Exception {
890  3 testTypes("/** @type {string} */ var a = 'a';" +
891    "/** @type {string} */ var b = 'b';" +
892    "/** @type {string} */ var c = a + b;");
893    }
894   
 
895  3 toggle public void testAdd4() throws Exception {
896  3 testTypes("/** @type {number} */ var a = 5;" +
897    "/** @type {string} */ var b = 'b';" +
898    "/** @type {string} */ var c = a + b;");
899    }
900   
 
901  3 toggle public void testAdd5() throws Exception {
902  3 testTypes("/** @type {string} */ var a = 'a';" +
903    "/** @type {number} */ var b = 5;" +
904    "/** @type {string} */ var c = a + b;");
905    }
906   
 
907  3 toggle public void testAdd6() throws Exception {
908  3 testTypes("/** @type {number} */ var a = 5;" +
909    "/** @type {number} */ var b = 5;" +
910    "/** @type {number} */ var c = a + b;");
911    }
912   
 
913  3 toggle public void testAdd7() throws Exception {
914  3 testTypes("/** @type {number} */ var a = 5;" +
915    "/** @type {string} */ var b = 'b';" +
916    "/** @type {number} */ var c = a + b;",
917    "initializing variable\n" +
918    "found : string\n" +
919    "required: number");
920    }
921   
 
922  3 toggle public void testAdd8() throws Exception {
923  3 testTypes("/** @type {string} */ var a = 'a';" +
924    "/** @type {number} */ var b = 5;" +
925    "/** @type {number} */ var c = a + b;",
926    "initializing variable\n" +
927    "found : string\n" +
928    "required: number");
929    }
930   
 
931  3 toggle public void testAdd9() throws Exception {
932  3 testTypes("/** @type {number} */ var a = 5;" +
933    "/** @type {number} */ var b = 5;" +
934    "/** @type {string} */ var c = a + b;",
935    "initializing variable\n" +
936    "found : number\n" +
937    "required: string");
938    }
939   
 
940  3 toggle public void testAdd10() throws Exception {
941    // d.e.f will have unknown type.
942  3 testTypes(
943    suppressMissingProperty("e", "f") +
944    "/** @type {number} */ var a = 5;" +
945    "/** @type {string} */ var c = a + d.e.f;");
946    }
947   
 
948  3 toggle public void testAdd11() throws Exception {
949    // d.e.f will have unknown type.
950  3 testTypes(
951    suppressMissingProperty("e", "f") +
952    "/** @type {number} */ var a = 5;" +
953    "/** @type {number} */ var c = a + d.e.f;");
954    }
955   
 
956  3 toggle public void testAdd12() throws Exception {
957  3 testTypes("/** @return {(number,string)} */ function a() { return 5; }" +
958    "/** @type {number} */ var b = 5;" +
959    "/** @type {boolean} */ var c = a() + b;",
960    "initializing variable\n" +
961    "found : (number|string)\n" +
962    "required: boolean");
963    }
964   
 
965  3 toggle public void testAdd13() throws Exception {
966  3 testTypes("/** @type {number} */ var a = 5;" +
967    "/** @return {(number,string)} */ function b() { return 5; }" +
968    "/** @type {boolean} */ var c = a + b();",
969    "initializing variable\n" +
970    "found : (number|string)\n" +
971    "required: boolean");
972    }
973   
 
974  3 toggle public void testAdd14() throws Exception {
975  3 testTypes("/** @type {(null,string)} */ var a = null;" +
976    "/** @type {number} */ var b = 5;" +
977    "/** @type {boolean} */ var c = a + b;",
978    "initializing variable\n" +
979    "found : (number|string)\n" +
980    "required: boolean");
981    }
982   
 
983  3 toggle public void testAdd15() throws Exception {
984  3 testTypes("/** @type {number} */ var a = 5;" +
985    "/** @return {(number,string)} */ function b() { return 5; }" +
986    "/** @type {boolean} */ var c = a + b();",
987    "initializing variable\n" +
988    "found : (number|string)\n" +
989    "required: boolean");
990    }
991   
 
992  3 toggle public void testAdd16() throws Exception {
993  3 testTypes("/** @type {(undefined,string)} */ var a = undefined;" +
994    "/** @type {number} */ var b = 5;" +
995    "/** @type {boolean} */ var c = a + b;",
996    "initializing variable\n" +
997    "found : (number|string)\n" +
998    "required: boolean");
999    }
1000   
 
1001  3 toggle public void testAdd17() throws Exception {
1002  3 testTypes("/** @type {number} */ var a = 5;" +
1003    "/** @type {(undefined,string)} */ var b = undefined;" +
1004    "/** @type {boolean} */ var c = a + b;",
1005    "initializing variable\n" +
1006    "found : (number|string)\n" +
1007    "required: boolean");
1008    }
1009   
 
1010  3 toggle public void testAdd18() throws Exception {
1011  3 testTypes("function f() {};" +
1012    "/** @type {string} */ var a = 'a';" +
1013    "/** @type {number} */ var c = a + f();",
1014    "initializing variable\n" +
1015    "found : string\n" +
1016    "required: number");
1017    }
1018   
 
1019  3 toggle public void testAdd19() throws Exception {
1020  3 testTypes("/** @param {number} opt_x\n@param {number} opt_y\n" +
1021    "@return {number} */ function f(opt_x, opt_y) {" +
1022    "return opt_x + opt_y;}");
1023    }
1024   
 
1025  3 toggle public void testAdd20() throws Exception {
1026  3 testTypes("/** @param {!Number} opt_x\n@param {!Number} opt_y\n" +
1027    "@return {number} */ function f(opt_x, opt_y) {" +
1028    "return opt_x + opt_y;}");
1029    }
1030   
 
1031  3 toggle public void testAdd21() throws Exception {
1032  3 testTypes("/** @param {Number|Boolean} opt_x\n" +
1033    "@param {number|boolean} opt_y\n" +
1034    "@return {number} */ function f(opt_x, opt_y) {" +
1035    "return opt_x + opt_y;}");
1036    }
1037   
 
1038  3 toggle public void testNumericComparison1() throws Exception {
1039  3 testTypes("/**@param {number} a*/ function f(a) {return a < 3;}");
1040    }
1041   
 
1042  3 toggle public void testNumericComparison2() throws Exception {
1043  3 testTypes("/**@param {!Object} a*/ function f(a) {return a < 3;}",
1044    "left side of numeric comparison\n" +
1045    "found : Object\n" +
1046    "required: number");
1047    }
1048   
 
1049  3 toggle public void testNumericComparison3() throws Exception {
1050  3 testTypes("/**@param {string} a*/ function f(a) {return a < 3;}");
1051    }
1052   
 
1053  3 toggle public void testNumericComparison4() throws Exception {
1054  3 testTypes("/**@param {(number,undefined)} a*/ " +
1055    "function f(a) {return a < 3;}");
1056    }
1057   
 
1058  3 toggle public void testNumericComparison5() throws Exception {
1059  3 testTypes("/**@param {*} a*/ function f(a) {return a < 3;}",
1060    "left side of numeric comparison\n" +
1061    "found : *\n" +
1062    "required: number");
1063    }
1064   
 
1065  3 toggle public void testNumericComparison6() throws Exception {
1066  3 testTypes("/**@return {void}*/ function foo() { if (3 >= foo()) return; }",
1067    "right side of numeric comparison\n" +
1068    "found : undefined\n" +
1069    "required: number");
1070    }
1071   
 
1072  3 toggle public void testStringComparison1() throws Exception {
1073  3 testTypes("/**@param {string} a*/ function f(a) {return a < 'x';}");
1074    }
1075   
 
1076  3 toggle public void testStringComparison2() throws Exception {
1077  3 testTypes("/**@param {Object} a*/ function f(a) {return a < 'x';}");
1078    }
1079   
 
1080  3 toggle public void testStringComparison3() throws Exception {
1081  3 testTypes("/**@param {number} a*/ function f(a) {return a < 'x';}");
1082    }
1083   
 
1084  3 toggle public void testStringComparison4() throws Exception {
1085  3 testTypes("/**@param {string|undefined} a*/ " +
1086    "function f(a) {return a < 'x';}");
1087    }
1088   
 
1089  3 toggle public void testStringComparison5() throws Exception {
1090  3 testTypes("/**@param {*} a*/ " +
1091    "function f(a) {return a < 'x';}");
1092    }
1093   
 
1094  3 toggle public void testStringComparison6() throws Exception {
1095  3 testTypes("/**@return {void} */ " +
1096    "function foo() { if ('a' >= foo()) return; }",
1097    "right side of comparison\n" +
1098    "found : undefined\n" +
1099    "required: string");
1100    }
1101   
 
1102  3 toggle public void testValueOfComparison1() throws Exception {
1103  3 testTypes("/** @constructor */function O() {};" +
1104    "/**@override*/O.prototype.valueOf = function() { return 1; };" +
1105    "/**@param {!O} a\n@param {!O} b*/ function f(a,b) { return a < b; }");
1106    }
1107   
 
1108  3 toggle public void testValueOfComparison2() throws Exception {
1109  3 testTypes("/** @constructor */function O() {};" +
1110    "/**@override*/O.prototype.valueOf = function() { return 1; };" +
1111    "/**@param {!O} a\n@param {number} b*/" +
1112    "function f(a,b) { return a < b; }");
1113    }
1114   
 
1115  3 toggle public void testValueOfComparison3() throws Exception {
1116  3 testTypes("/** @constructor */function O() {};" +
1117    "/**@override*/O.prototype.toString = function() { return 'o'; };" +
1118    "/**@param {!O} a\n@param {string} b*/" +
1119    "function f(a,b) { return a < b; }");
1120    }
1121   
 
1122  3 toggle public void testGenericRelationalExpression() throws Exception {
1123  3 testTypes("/**@param {*} a\n@param {*} b*/ " +
1124    "function f(a,b) {return a < b;}");
1125    }
1126   
 
1127  3 toggle public void testInstanceof1() throws Exception {
1128  3 testTypes("function foo(){" +
1129    "if (bar instanceof 3)return;}",
1130    "instanceof requires an object\n" +
1131    "found : number\n" +
1132    "required: Object");
1133    }
1134   
 
1135  3 toggle public void testInstanceof2() throws Exception {
1136  3 testTypes("/**@return {void}*/function foo(){" +
1137    "if (foo() instanceof Object)return;}",
1138    "deterministic instanceof yields false\n" +
1139    "found : undefined\n" +
1140    "required: NoObject");
1141    }
1142   
 
1143  3 toggle public void testInstanceof3() throws Exception {
1144  3 testTypes("/**@return {*} */function foo(){" +
1145    "if (foo() instanceof Object)return;}");
1146    }
1147   
 
1148  3 toggle public void testInstanceof4() throws Exception {
1149  3 testTypes("/**@return {(Object|number)} */function foo(){" +
1150    "if (foo() instanceof Object)return 3;}");
1151    }
1152   
 
1153  3 toggle public void testInstanceof5() throws Exception {
1154    // No warning for unknown types.
1155  3 testTypes("/** @return {?} */ function foo(){" +
1156    "if (foo() instanceof Object)return;}");
1157    }
1158   
 
1159  3 toggle public void testInstanceof6() throws Exception {
1160  3 testTypes("/**@return {(Array|number)} */function foo(){" +
1161    "if (foo() instanceof Object)return 3;}");
1162    }
1163   
 
1164  3 toggle public void testInstanceOfReduction3() throws Exception {
1165  3 testTypes(
1166    "/** \n" +
1167    " * @param {Object} x \n" +
1168    " * @param {Function} y \n" +
1169    " * @return {boolean} \n" +
1170    " */\n" +
1171    "var f = function(x, y) {\n" +
1172    " return x instanceof y;\n" +
1173    "};");
1174    }
1175   
 
1176  3 toggle public void testScoping1() throws Exception {
1177  3 testTypes(
1178    "/**@param {string} a*/function foo(a){" +
1179    " /**@param {Array|string} a*/function bar(a){" +
1180    " if (a instanceof Array)return;" +
1181    " }" +
1182    "}");
1183    }
1184   
 
1185  3 toggle public void testScoping2() throws Exception {
1186  3 testTypes(
1187    "/** @type number */ var a;" +
1188    "function Foo() {" +
1189    " /** @type string */ var a;" +
1190    "}");
1191    }
1192   
 
1193  3 toggle public void testScoping3() throws Exception {
1194  3 testTypes("\n\n/** @type{Number}*/var b;\n/** @type{!String} */var b;",
1195    "variable b redefined with type String, original " +
1196    "definition at [testcode]:3 with type (Number|null|undefined)");
1197    }
1198   
 
1199  3 toggle public void testScoping4() throws Exception {
1200  3 testTypes("/** @type{Number}*/var b; if (true) /** @type{!String} */var b;",
1201    "variable b redefined with type String, original " +
1202    "definition at [testcode]:1 with type (Number|null|undefined)");
1203    }
1204   
 
1205  3 toggle public void testScoping5() throws Exception {
1206    // multiple definitions are not checked by the type checker but by a
1207    // subsequent pass
1208  3 testTypes("if (true) var b; var b;");
1209    }
1210   
 
1211  3 toggle public void testScoping6() throws Exception {
1212    // multiple definitions are not checked by the type checker but by a
1213    // subsequent pass
1214  3 testTypes("if (true) var b; if (true) var b;");
1215    }
1216   
 
1217  3 toggle public void testScoping7() throws Exception {
1218  3 testTypes("/** @constructor */function A() {" +
1219    " /** @type !A */this.a = null;" +
1220    "}",
1221    "assignment to property a of A\n" +
1222    "found : null\n" +
1223    "required: A");
1224    }
1225   
 
1226  3 toggle public void testScoping8() throws Exception {
1227  3 testTypes("/** @constructor */function A() {}" +
1228    "/** @constructor */function B() {" +
1229    " /** @type !A */this.a = null;" +
1230    "}",
1231    "assignment to property a of B\n" +
1232    "found : null\n" +
1233    "required: A");
1234    }
1235   
 
1236  3 toggle public void testScoping9() throws Exception {
1237  3 testTypes("/** @constructor */function B() {" +
1238    " /** @type !A */this.a = null;" +
1239    "}" +
1240    "/** @constructor */function A() {}",
1241    "assignment to property a of B\n" +
1242    "found : null\n" +
1243    "required: A");
1244    }
1245   
 
1246  3 toggle public void testScoping10() throws Exception {
1247  3 TypeCheckResult p = parseAndTypeCheckWithScope("var a = function b(){};");
1248   
1249    // a declared, b is not
1250  3 assertTrue(p.scope.isDeclared("a", false));
1251  3 assertFalse(p.scope.isDeclared("b", false));
1252   
1253    // checking that a has the correct assigned type
1254  3 assertEquals("function (): undefined",
1255    p.scope.getVar("a").getType().toString());
1256    }
1257   
 
1258  3 toggle public void testScoping11() throws Exception {
1259    // named anonymous functions create a binding in their body only
1260    // the return is wrong but the assignment is OK since the type of b is ?
1261  3 testTypes(
1262    "/** @return {number} */var a = function b(){ return b };",
1263    "inconsistent return type\n" +
1264    "found : function (): number\n" +
1265    "required: number");
1266    }
1267   
 
1268  3 toggle public void testFunctionArguments1() throws Exception {
1269  3 testFunctionType(
1270    "/** @param {number} a\n@return {string} */" +
1271    "function f(a) {}",
1272    "function (number): string");
1273    }
1274   
 
1275  3 toggle public void testFunctionArguments2() throws Exception {
1276  3 testFunctionType(
1277    "/** @param {number} opt_a\n@return {string} */" +
1278    "function f(opt_a) {}",
1279    "function (number=): string");
1280    }
1281   
 
1282  3 toggle public void testFunctionArguments3() throws Exception {
1283  3 testFunctionType(
1284    "/** @param {number} b\n@return {string} */" +
1285    "function f(a,b) {}",
1286    "function (?, number): string");
1287    }
1288   
 
1289  3 toggle public void testFunctionArguments4() throws Exception {
1290  3 testFunctionType(
1291    "/** @param {number} opt_a\n@return {string} */" +
1292    "function f(a,opt_a) {}",
1293    "function (?, number=): string");
1294    }
1295   
 
1296  3 toggle public void testFunctionArguments5() throws Exception {
1297  3 testTypes(
1298    "function a(opt_a,a) {}",
1299    "optional arguments must be at the end");
1300    }
1301   
 
1302  3 toggle public void testFunctionArguments6() throws Exception {
1303  3 testTypes(
1304    "function a(var_args,a) {}",
1305    "variable length argument must be last");
1306    }
1307   
 
1308  3 toggle public void testFunctionArguments7() throws Exception {
1309  3 testTypes(
1310    "/** @param {number} opt_a\n@return {string} */" +
1311    "function a(a,opt_a,var_args) {}");
1312    }
1313   
 
1314  3 toggle public void testFunctionArguments8() throws Exception {
1315  3 testTypes(
1316    "function a(a,opt_a,var_args,b) {}",
1317    "variable length argument must be last");
1318    }
1319   
 
1320  3 toggle public void testFunctionArguments9() throws Exception {
1321    // testing that only one error is reported
1322  3 testTypes(
1323    "function a(a,opt_a,var_args,b,c) {}",
1324    "variable length argument must be last");
1325    }
1326   
 
1327  3 toggle public void testFunctionArguments10() throws Exception {
1328    // testing that only one error is reported
1329  3 testTypes(
1330    "function a(a,opt_a,b,c) {}",
1331    "optional arguments must be at the end");
1332    }
1333   
 
1334  3 toggle public void testFunctionArguments11() throws Exception {
1335  3 testTypes(
1336    "function a(a,opt_a,b,c,var_args,d) {}",
1337    "optional arguments must be at the end");
1338    }
1339   
 
1340  3 toggle public void testFunctionArguments12() throws Exception {
1341  3 testTypes("/** @param foo {String} */function bar(baz){}",
1342    "parameter foo does not appear in bar's parameter list");
1343    }
1344   
 
1345  3 toggle public void testFunctionArguments13() throws Exception {
1346    // verifying that the argument type have non-inferable types
1347  3 testTypes(
1348    "/** @return {boolean} */ function u() { return true; }" +
1349    "/** @param {boolean} b\n@return {?boolean} */" +
1350    "function f(b) { if (u()) { b = null; } return b; }",
1351    "assignment\n" +
1352    "found : null\n" +
1353    "required: boolean");
1354    }
1355   
 
1356  3 toggle public void testFunctionArguments14() throws Exception {
1357  3 testTypes(
1358    "/**\n" +
1359    " * @param {string} x\n" +
1360    " * @param {number} opt_y\n" +
1361    " * @param {boolean} var_args\n" +
1362    " */ function f(x, opt_y, var_args) {}" +
1363    "f('3'); f('3', 2); f('3', 2, true); f('3', 2, true, false);");
1364    }
1365   
 
1366  3 toggle public void testFunctionArguments15() throws Exception {
1367  3 testTypes(
1368    "/** @param {?function(*)} f */" +
1369    "function g(f) { f(1, 2); }",
1370    "Function f: called with 2 argument(s). " +
1371    "Function requires at least 1 argument(s) " +
1372    "and no more than 1 argument(s).");
1373    }
1374   
 
1375  3 toggle public void testPrintFunctionName1() throws Exception {
1376    // Ensures that the function name is pretty.
1377  3 testTypes(
1378    "var goog = {}; goog.run = function(f) {};" +
1379    "goog.run();",
1380    "Function goog.run: called with 0 argument(s). " +
1381    "Function requires at least 1 argument(s) " +
1382    "and no more than 1 argument(s).");
1383    }
1384   
 
1385  3 toggle public void testPrintFunctionName2() throws Exception {
1386  3 testTypes(
1387    "/** @constructor */ var Foo = function() {}; " +
1388    "Foo.prototype.run = function(f) {};" +
1389    "(new Foo).run();",
1390    "Function Foo.prototype.run: called with 0 argument(s). " +
1391    "Function requires at least 1 argument(s) " +
1392    "and no more than 1 argument(s).");
1393    }
1394   
 
1395  3 toggle public void testFunctionInference1() throws Exception {
1396  3 testFunctionType(
1397    "function f(a) {}",
1398    "function (?): undefined");
1399    }
1400   
 
1401  3 toggle public void testFunctionInference2() throws Exception {
1402  3 testFunctionType(
1403    "function f(a,b) {}",
1404    "function (?, ?): undefined");
1405    }
1406   
 
1407  3 toggle public void testFunctionInference3() throws Exception {
1408  3 testFunctionType(
1409    "function f(var_args) {}",
1410    "function (...[?]): undefined");
1411    }
1412   
 
1413  3 toggle public void testFunctionInference4() throws Exception {
1414  3 testFunctionType(
1415    "function f(a,b,c,var_args) {}",
1416    "function (?, ?, ?, ...[?]): undefined");
1417    }
1418   
 
1419  3 toggle public void testFunctionInference5() throws Exception {
1420  3 testFunctionType(
1421    "/** @this Date\n@return {string} */function f(a) {}",
1422    "function (this:Date, ?): string");
1423    }
1424   
 
1425  3 toggle public void testFunctionInference6() throws Exception {
1426  3 testFunctionType(
1427    "/** @this Date\n@return {string} */function f(opt_a) {}",
1428    "function (this:Date, ?=): string");
1429    }
1430   
 
1431  3 toggle public void testFunctionInference7() throws Exception {
1432  3 testFunctionType(
1433    "/** @this Date */function f(a,b,c,var_args) {}",
1434    "function (this:Date, ?, ?, ?, ...[?]): undefined");
1435    }
1436   
 
1437  3 toggle public void testFunctionInference8() throws Exception {
1438  3 testFunctionType(
1439    "function f() {}",
1440    "function (): undefined");
1441    }
1442   
 
1443  3 toggle public void testFunctionInference9() throws Exception {
1444  3 testFunctionType(
1445    "var f = function() {};",
1446    "function (): undefined");
1447    }
1448   
 
1449  3 toggle public void testFunctionInference10() throws Exception {
1450  3 testFunctionType(
1451    "/** @this Date\n@param {boolean} b\n@return {string} */" +
1452    "var f = function(a,b) {};",
1453    "function (this:Date, ?, boolean): string");
1454    }
1455   
 
1456  3 toggle public void testFunctionInference11() throws Exception {
1457  3 testFunctionType(
1458    "var goog = {};" +
1459    "/** @return {number}*/goog.f = function(){};",
1460    "goog.f",
1461    "function (): number");
1462    }
1463   
 
1464  3 toggle public void testFunctionInference12() throws Exception {
1465  3 testFunctionType(
1466    "var goog = {};" +
1467    "goog.f = function(){};",
1468    "goog.f",
1469    "function (): undefined");
1470    }
1471   
 
1472  3 toggle public void testFunctionInference13() throws Exception {
1473  3 testFunctionType(
1474    "var goog = {};" +
1475    "/** @constructor */ goog.Foo = function(){};" +
1476    "/** @param {!goog.Foo} f */function eatFoo(f){};",
1477    "eatFoo",
1478    "function (goog.Foo): undefined");
1479    }
1480   
 
1481  3 toggle public void testFunctionInference14() throws Exception {
1482  3 testFunctionType(
1483    "var goog = {};" +
1484    "/** @constructor */ goog.Foo = function(){};" +
1485    "/** @return {!goog.Foo} */function eatFoo(){ return new goog.Foo; };",
1486    "eatFoo",
1487    "function (): goog.Foo");
1488    }
1489   
 
1490  3 toggle public void testFunctionInference15() throws Exception {
1491  3 testFunctionType(
1492    "/** @constructor */ function f() {};" +
1493    "f.prototype.foo = function(){};",
1494    "f.prototype.foo",
1495    "function (this:f): undefined");
1496    }
1497   
 
1498  3 toggle public void testFunctionInference16() throws Exception {
1499  3 testFunctionType(
1500    "/** @constructor */ function f() {};" +
1501    "f.prototype.foo = function(){};",
1502    "(new f).foo",
1503    "function (this:f): undefined");
1504    }
1505   
 
1506  3 toggle public void testFunctionInference17() throws Exception {
1507  3 testFunctionType(
1508    "/** @constructor */ function f() {}" +
1509    "function abstractMethod() {}" +
1510    "/** @param {number} x */ f.prototype.foo = abstractMethod;",
1511    "(new f).foo",
1512    "function (this:f, number): ?");
1513    }
1514   
 
1515  3 toggle public void testFunctionInference18() throws Exception {
1516  3 testFunctionType(
1517    "var goog = {};" +
1518    "/** @this {Date} */ goog.eatWithDate;",
1519    "goog.eatWithDate",
1520    "function (this:Date): ?");
1521    }
1522   
 
1523  3 toggle public void testFunctionInference19() throws Exception {
1524  3 testFunctionType(
1525    "/** @param {string} x */ var f;",
1526    "f",
1527    "function (string): ?");
1528    }
1529   
 
1530  3 toggle public void testFunctionInference20() throws Exception {
1531  3 testFunctionType(
1532    "/** @this {Date} */ var f;",
1533    "f",
1534    "function (this:Date): ?");
1535    }
1536   
 
1537  3 toggle public void testInnerFunction1() throws Exception {
1538  3 testTypes(
1539    "function f() {" +
1540    " /** @type {number} */ var x = 3;\n" +
1541    " function g() { x = null; }" +
1542    " return x;" +
1543    "}",
1544    "assignment\n" +
1545    "found : null\n" +
1546    "required: number");
1547    }
1548   
 
1549  3 toggle public void testInnerFunction2() throws Exception {
1550  3 testTypes(
1551    "/** @return {number} */\n" +
1552    "function f() {" +
1553    " var x = null;\n" +
1554    " function g() { x = 3; }" +
1555    " g();" +
1556    " return x;" +
1557    "}",
1558    "inconsistent return type\n" +
1559    "found : (null|number)\n" +
1560    "required: number");
1561    }
1562   
 
1563  3 toggle public void testInnerFunction3() throws Exception {
1564  3 testTypes(
1565    "var x = null;" +
1566    "/** @return {number} */\n" +
1567    "function f() {" +
1568    " x = 3;\n" +
1569    " /** @return {number} */\n" +
1570    " function g() { x = true; return x; }" +
1571    " return x;" +
1572    "}",
1573    "inconsistent return type\n" +
1574    "found : boolean\n" +
1575    "required: number");
1576    }
1577   
 
1578  3 toggle public void testInnerFunction4() throws Exception {
1579  3 testTypes(
1580    "var x = null;" +
1581    "/** @return {number} */\n" +
1582    "function f() {" +
1583    " x = '3';\n" +
1584    " /** @return {number} */\n" +
1585    " function g() { x = 3; return x; }" +
1586    " return x;" +
1587    "}",
1588    "inconsistent return type\n" +
1589    "found : string\n" +
1590    "required: number");
1591    }
1592   
 
1593  3 toggle public void testInnerFunction5() throws Exception {
1594  3 testTypes(
1595    "/** @return {number} */\n" +
1596    "function f() {" +
1597    " var x = 3;\n" +
1598    " /** @return {number} */" +
1599    " function g() { var x = 3;x = true; return x; }" +
1600    " return x;" +
1601    "}",
1602    "inconsistent return type\n" +
1603    "found : boolean\n" +
1604    "required: number");
1605    }
1606   
 
1607  3 toggle public void testInnerFunction6() throws Exception {
1608  3 testClosureTypes(
1609    CLOSURE_DEFS +
1610    "function f() {" +
1611    " var x = 0 || function() {};\n" +
1612    " function g() { if (goog.isFunction(x)) { x(1); } }" +
1613    " g();" +
1614    "}",
1615    "Function x: called with 1 argument(s). " +
1616    "Function requires at least 0 argument(s) " +
1617    "and no more than 0 argument(s).");
1618    }
1619   
 
1620  3 toggle public void testInnerFunction7() throws Exception {
1621  3 testClosureTypes(
1622    CLOSURE_DEFS +
1623    "function f() {" +
1624    " /** @type {number|function()} */" +
1625    " var x = 0 || function() {};\n" +
1626    " function g() { if (goog.isFunction(x)) { x(1); } }" +
1627    " g();" +
1628    "}",
1629    "Function x: called with 1 argument(s). " +
1630    "Function requires at least 0 argument(s) " +
1631    "and no more than 0 argument(s).");
1632    }
1633   
 
1634  3 toggle public void testInnerFunction8() throws Exception {
1635  3 testClosureTypes(
1636    CLOSURE_DEFS +
1637    "function f() {" +
1638    " function x() {};\n" +
1639    " function g() { if (goog.isFunction(x)) { x(1); } }" +
1640    " g();" +
1641    "}",
1642    "Function x: called with 1 argument(s). " +
1643    "Function requires at least 0 argument(s) " +
1644    "and no more than 0 argument(s).");
1645    }
1646   
 
1647  3 toggle public void testInnerFunction9() throws Exception {
1648  3 testTypes(
1649    "function f() {" +
1650    " var x = 3;\n" +
1651    " function g() { x = null; };\n" +
1652    " function h() { return x == null; }" +
1653    " return h();" +
1654    "}");
1655    }
1656   
 
1657  3 toggle public void testAbstractMethodHandling1() throws Exception {
1658  3 testTypes(
1659    "/** @type {Function} */ var abstractFn = function() {};" +
1660    "abstractFn(1);");
1661    }
1662   
 
1663  3 toggle public void testAbstractMethodHandling2() throws Exception {
1664  3 testTypes(
1665    "var abstractFn = function() {};" +
1666    "abstractFn(1);",
1667    "Function abstractFn: called with 1 argument(s). " +
1668    "Function requires at least 0 argument(s) " +
1669    "and no more than 0 argument(s).");
1670    }
1671   
 
1672  3 toggle public void testAbstractMethodHandling3() throws Exception {
1673  3 testTypes(
1674    "var goog = {};" +
1675    "/** @type {Function} */ goog.abstractFn = function() {};" +
1676    "goog.abstractFn(1);");
1677    }
1678   
 
1679  3 toggle public void testAbstractMethodHandling4() throws Exception {
1680  3 testTypes(
1681    "var goog = {};" +
1682    "goog.abstractFn = function() {};" +
1683    "goog.abstractFn(1);",
1684    "Function goog.abstractFn: called with 1 argument(s). " +
1685    "Function requires at least 0 argument(s) " +
1686    "and no more than 0 argument(s).");
1687    }
1688   
 
1689  3 toggle public void testAbstractMethodHandling5() throws Exception {
1690  3 testTypes(
1691    "/** @type {!Function} */ var abstractFn = function() {};" +
1692    "/** @param {number} x */ var f = abstractFn;" +
1693    "f('x');",
1694    "actual parameter 1 of f does not match formal parameter\n" +
1695    "found : string\n" +
1696    "required: number");
1697    }
1698   
 
1699  3 toggle public void testAbstractMethodHandling6() throws Exception {
1700  3 testTypes(
1701    "var goog = {};" +
1702    "/** @type {Function} */ goog.abstractFn = function() {};" +
1703    "/** @param {number} x */ goog.f = abstractFn;" +
1704    "goog.f('x');",
1705    "actual parameter 1 of goog.f does not match formal parameter\n" +
1706    "found : string\n" +
1707    "required: number");
1708    }
1709   
 
1710  3 toggle public void testMethodInference1() throws Exception {
1711  3 testTypes(
1712    "/** @constructor */ function F() {}" +
1713    "/** @return {number} */ F.prototype.foo = function() { return 3; };" +
1714    "/** @constructor \n * @extends {F} */ " +
1715    "function G() {}" +
1716    "/** @override */ G.prototype.foo = function() { return true; };",
1717    "inconsistent return type\n" +
1718    "found : boolean\n" +
1719    "required: number");
1720    }
1721   
 
1722  3 toggle public void testMethodInference2() throws Exception {
1723  3 testTypes(
1724    "var goog = {};" +
1725    "/** @constructor */ goog.F = function() {};" +
1726    "/** @return {number} */ goog.F.prototype.foo = " +
1727    " function() { return 3; };" +
1728    "/** @constructor \n * @extends {goog.F} */ " +
1729    "goog.G = function() {};" +
1730    "/** @override */ goog.G.prototype.foo = function() { return true; };",
1731    "inconsistent return type\n" +
1732    "found : boolean\n" +
1733    "required: number");
1734    }
1735   
 
1736  3 toggle public void testMethodInference3() throws Exception {
1737  3 testTypes(
1738    "/** @constructor */ function F() {}" +
1739    "/** @param {boolean} x \n * @return {number} */ " +
1740    "F.prototype.foo = function(x) { return 3; };" +
1741    "/** @constructor \n * @extends {F} */ " +
1742    "function G() {}" +
1743    "/** @override */ " +
1744    "G.prototype.foo = function(x) { return x; };",
1745    "inconsistent return type\n" +
1746    "found : boolean\n" +
1747    "required: number");
1748    }
1749   
 
1750  3 toggle public void testMethodInference4() throws Exception {
1751  3 testTypes(
1752    "/** @constructor */ function F() {}" +
1753    "/** @param {boolean} x \n * @return {number} */ " +
1754    "F.prototype.foo = function(x) { return 3; };" +
1755    "/** @constructor \n * @extends {F} */ " +
1756    "function G() {}" +
1757    "/** @override */ " +
1758    "G.prototype.foo = function(y) { return y; };",
1759    "inconsistent return type\n" +
1760    "found : boolean\n" +
1761    "required: number");
1762    }
1763   
 
1764  3 toggle public void testMethodInference5() throws Exception {
1765  3 testTypes(
1766    "/** @constructor */ function F() {}" +
1767    "/** @param {number} x \n * @return {string} */ " +
1768    "F.prototype.foo = function(x) { return 'x'; };" +
1769    "/** @constructor \n * @extends {F} */ " +
1770    "function G() {}" +
1771    "/** @type {number} */ G.prototype.num = 3;" +
1772    "/** @override */ " +
1773    "G.prototype.foo = function(y) { return this.num + y; };",
1774    "inconsistent return type\n" +
1775    "found : number\n" +
1776    "required: string");
1777    }
1778   
 
1779  3 toggle public void testMethodInference6() throws Exception {
1780  3 testTypes(
1781    "/** @constructor */ function F() {}" +
1782    "/** @param {number} x */ F.prototype.foo = function(x) { };" +
1783    "/** @constructor \n * @extends {F} */ " +
1784    "function G() {}" +
1785    "/** @override */ G.prototype.foo = function() { };" +
1786    "(new G()).foo(1);");
1787    }
1788   
 
1789  3 toggle public void testMethodInference7() throws Exception {
1790  3 testTypes(
1791    "/** @constructor */ function F() {}" +
1792    "F.prototype.foo = function() { };" +
1793    "/** @constructor \n * @extends {F} */ " +
1794    "function G() {}" +
1795    "/** @override */ G.prototype.foo = function(x, y) { };",
1796    "mismatch of the foo property type and the type of the property " +
1797    "it overrides from superclass F\n" +
1798    "original: function (this:F): undefined\n" +
1799    "override: function (this:G, ?, ?): undefined");
1800    }
1801   
 
1802  3 toggle public void testMethodInference8() throws Exception {
1803  3 testTypes(
1804    "/** @constructor */ function F() {}" +
1805    "F.prototype.foo = function() { };" +
1806    "/** @constructor \n * @extends {F} */ " +
1807    "function G() {}" +
1808    "/** @override */ " +
1809    "G.prototype.foo = function(opt_b, var_args) { };" +
1810    "(new G()).foo(1, 2, 3);");
1811    }
1812   
 
1813  3 toggle public void testMethodInference9() throws Exception {
1814  3 testTypes(
1815    "/** @constructor */ function F() {}" +
1816    "F.prototype.foo = function() { };" +
1817    "/** @constructor \n * @extends {F} */ " +
1818    "function G() {}" +
1819    "/** @override */ " +
1820    "G.prototype.foo = function(var_args, opt_b) { };",
1821    "variable length argument must be last");
1822    }
1823   
 
1824  3 toggle public void testStaticMethodDeclaration1() throws Exception {
1825  3 testTypes(
1826    "/** @constructor */ function F() { F.foo(true); }" +
1827    "/** @param {number} x */ F.foo = function(x) {};",
1828    "actual parameter 1 of F.foo does not match formal parameter\n" +
1829    "found : boolean\n" +
1830    "required: number");
1831    }
1832   
 
1833  3 toggle public void testStaticMethodDeclaration2() throws Exception {
1834  3 testTypes(
1835    "var goog = goog || {}; function f() { goog.foo(true); }" +
1836    "/** @param {number} x */ goog.foo = function(x) {};",
1837    "actual parameter 1 of goog.foo does not match formal parameter\n" +
1838    "found : boolean\n" +
1839    "required: number");
1840    }
1841   
 
1842  3 toggle public void testStaticMethodDeclaration3() throws Exception {
1843  3 testTypes(
1844    "var goog = goog || {}; function f() { goog.foo(true); }" +
1845    "goog.foo = function() {};",
1846    "Function goog.foo: called with 1 argument(s). Function requires " +
1847    "at least 0 argument(s) and no more than 0 argument(s).");
1848    }
1849   
 
1850  3 toggle public void testDuplicateStaticMethodDecl1() throws Exception {
1851  3 testTypes(
1852    "var goog = goog || {};" +
1853    "/** @param {number} x */ goog.foo = function(x) {};" +
1854    "/** @param {number} x */ goog.foo = function(x) {};",
1855    "variable goog.foo redefined with type function (number): undefined, " +
1856    "original definition at [testcode]:1 " +
1857    "with type function (number): undefined");
1858    }
1859   
 
1860  3 toggle public void testDuplicateStaticMethodDecl2() throws Exception {
1861  3 testTypes(
1862    "var goog = goog || {};" +
1863    "/** @param {number} x */ goog.foo = function(x) {};" +
1864    "/** @param {number} x \n * @suppress {duplicate} */ " +
1865    "goog.foo = function(x) {};");
1866    }
1867   
 
1868  3 toggle public void testDuplicateStaticMethodDecl3() throws Exception {
1869  3 testTypes(
1870    "var goog = goog || {};" +
1871    "goog.foo = function(x) {};" +
1872    "goog.foo = function(x) {};");
1873    }
1874   
 
1875  3 toggle public void testDuplicateStaticMethodDecl4() throws Exception {
1876  3 testTypes(
1877    "var goog = goog || {};" +
1878    "/** @type {Function} */ goog.foo = function(x) {};" +
1879    "goog.foo = function(x) {};");
1880    }
1881   
 
1882  3 toggle public void testDuplicateStaticMethodDecl5() throws Exception {
1883  3 testTypes(
1884    "var goog = goog || {};" +
1885    "goog.foo = function(x) {};" +
1886    "/** @return {undefined} */ goog.foo = function(x) {};",
1887    "variable goog.foo redefined with type function (?): undefined, " +
1888    "original definition at [testcode]:1 with type " +
1889    "function (?): undefined");
1890    }
1891   
 
1892  3 toggle public void testDuplicateStaticPropertyDecl1() throws Exception {
1893  3 testTypes(
1894    "var goog = goog || {};" +
1895    "/** @type {Foo} */ goog.foo;" +
1896    "/** @type {Foo} */ goog.foo;" +
1897    "/** @constructor */ function Foo() {}");
1898    }
1899   
 
1900  3 toggle public void testDuplicateStaticPropertyDecl2() throws Exception {
1901  3 testTypes(
1902    "var goog = goog || {};" +
1903    "/** @type {Foo} */ goog.foo;" +
1904    "/** @type {Foo} \n * @suppress {duplicate} */ goog.foo;" +
1905    "/** @constructor */ function Foo() {}");
1906    }
1907   
 
1908  3 toggle public void testDuplicateStaticPropertyDecl3() throws Exception {
1909  3 testTypes(
1910    "var goog = goog || {};" +
1911    "/** @type {!Foo} */ goog.foo;" +
1912    "/** @type {string} */ goog.foo;" +
1913    "/** @constructor */ function Foo() {}",
1914    "variable goog.foo redefined with type string, " +
1915    "original definition at [testcode]:1 with type Foo");
1916    }
1917   
 
1918  3 toggle public void testDuplicateStaticPropertyDecl4() throws Exception {
1919  3 testClosureTypesMultipleWarnings(
1920    "var goog = goog || {};" +
1921    "/** @type {!Foo} */ goog.foo;" +
1922    "/** @type {string} */ goog.foo = 'x';" +
1923    "/** @constructor */ function Foo() {}",
1924    Lists.newArrayList(
1925    "assignment to property foo of goog\n" +
1926    "found : string\n" +
1927    "required: Foo",
1928    "variable goog.foo redefined with type string, " +
1929    "original definition at [testcode]:1 with type Foo"));
1930    }
1931   
 
1932  3 toggle public void testDuplicateStaticPropertyDecl5() throws Exception {
1933  3 testClosureTypesMultipleWarnings(
1934    "var goog = goog || {};" +
1935    "/** @type {!Foo} */ goog.foo;" +
1936    "/** @type {string}\n * @suppress {duplicate} */ goog.foo = 'x';" +
1937    "/** @constructor */ function Foo() {}",
1938    Lists.newArrayList(
1939    "assignment to property foo of goog\n" +
1940    "found : string\n" +
1941    "required: Foo",
1942    "variable goog.foo redefined with type string, " +
1943    "original definition at [testcode]:1 with type Foo"));
1944    }
1945   
 
1946  3 toggle public void testDuplicateStaticPropertyDecl6() throws Exception {
1947  3 testTypes(
1948    "var goog = goog || {};" +
1949    "/** @type {string} */ goog.foo = 'y';" +
1950    "/** @type {string}\n * @suppress {duplicate} */ goog.foo = 'x';");
1951    }
1952   
 
1953  3 toggle public void testDuplicateStaticPropertyDecl7() throws Exception {
1954  3 testTypes(
1955    "var goog = goog || {};" +
1956    "/** @param {string} x */ goog.foo;" +
1957    "/** @type {function(string)} */ goog.foo;");
1958    }
1959   
 
1960  3 toggle public void testDuplicateStaticPropertyDecl8() throws Exception {
1961  3 testTypes(
1962    "var goog = goog || {};" +
1963    "/** @return {EventCopy} */ goog.foo;" +
1964    "/** @constructor */ function EventCopy() {}" +
1965    "/** @return {EventCopy} */ goog.foo;");
1966    }
1967   
 
1968  3 toggle public void testDuplicateStaticPropertyDecl9() throws Exception {
1969  3 testTypes(
1970    "var goog = goog || {};" +
1971    "/** @return {EventCopy} */ goog.foo;" +
1972    "/** @return {EventCopy} */ goog.foo;" +
1973    "/** @constructor */ function EventCopy() {}");
1974    }
1975   
 
1976  3 toggle public void testDuplicateLocalVarDecl() throws Exception {
1977  3 testClosureTypesMultipleWarnings(
1978    "/** @param {number} x */\n" +
1979    "function f(x) { /** @type {string} */ var x = ''; }",
1980    Lists.newArrayList(
1981    "variable x redefined with type string, original definition" +
1982    " at [testcode]:2 with type number",
1983    "initializing variable\n" +
1984    "found : string\n" +
1985    "required: number"));
1986    }
1987   
 
1988  3 toggle public void testStubFunctionDeclaration1() throws Exception {
1989  3 testFunctionType(
1990    "/** @constructor */ function f() {};" +
1991    "/** @param {number} x \n * @param {string} y \n" +
1992    " * @return {number} */ f.prototype.foo;",
1993    "(new f).foo",
1994    "function (this:f, number, string): number");
1995    }
1996   
 
1997  3 toggle public void testStubFunctionDeclaration2() throws Exception {
1998  3 testExternFunctionType(
1999    // externs
2000    "/** @constructor */ function f() {};" +
2001    "/** @constructor \n * @extends {f} */ f.subclass;",
2002    "f.subclass",
2003    "function (new:f.subclass): ?");
2004    }
2005   
 
2006  3 toggle public void testStubFunctionDeclaration3() throws Exception {
2007  3 testFunctionType(
2008    "/** @constructor */ function f() {};" +
2009    "/** @return {undefined} */ f.foo;",
2010    "f.foo",
2011    "function (): undefined");
2012    }
2013   
 
2014  3 toggle public void testStubFunctionDeclaration4() throws Exception {
2015  3 testFunctionType(
2016    "/** @constructor */ function f() { " +
2017    " /** @return {number} */ this.foo;" +
2018    "}",
2019    "(new f).foo",
2020    "function (this:f): number");
2021    }
2022   
 
2023  3 toggle public void testStubFunctionDeclaration5() throws Exception {
2024  3 testFunctionType(
2025    "/** @constructor */ function f() { " +
2026    " /** @type {Function} */ this.foo;" +
2027    "}",
2028    "(new f).foo",
2029    createOptionalType(createNullableType(U2U_CONSTRUCTOR_TYPE))
2030    .toString());
2031    }
2032   
 
2033  3 toggle public void testStubFunctionDeclaration6() throws Exception {
2034  3 testFunctionType(
2035    "/** @constructor */ function f() {} " +
2036    "/** @type {Function} */ f.prototype.foo;",
2037    "(new f).foo",
2038    createOptionalType(createNullableType(U2U_CONSTRUCTOR_TYPE))
2039    .toString());
2040    }
2041   
 
2042  3 toggle public void testStubFunctionDeclaration7() throws Exception {
2043  3 testFunctionType(
2044    "/** @constructor */ function f() {} " +
2045    "/** @type {Function} */ f.prototype.foo = function() {};",
2046    "(new f).foo",
2047    createOptionalType(createNullableType(U2U_CONSTRUCTOR_TYPE))
2048    .toString());
2049    }
2050   
 
2051  3 toggle public void testStubFunctionDeclaration8() throws Exception {
2052  3 testFunctionType(
2053    "/** @type {Function} */ var f = function() {}; ",
2054    "f",
2055    createOptionalType(createNullableType(U2U_CONSTRUCTOR_TYPE))
2056    .toString());
2057    }
2058   
 
2059  3 toggle public void testStubFunctionDeclaration9() throws Exception {
2060  3 testFunctionType(
2061    "/** @type {function():number} */ var f; ",
2062    "f",
2063    "function (): number");
2064    }
2065   
 
2066  3 toggle public void testStubFunctionDeclaration10() throws Exception {
2067  3 testFunctionType(
2068    "/** @type {function(number):number} */ var f = function(x) {};",
2069    "f",
2070    "function (number): number");
2071    }
2072   
 
2073  3 toggle public void testNestedFunctionInference1() throws Exception {
2074  3 String nestedAssignOfFooAndBar =
2075    "/** @constructor */ function f() {};" +
2076    "f.prototype.foo = f.prototype.bar = function(){};";
2077  3 testFunctionType(nestedAssignOfFooAndBar, "(new f).bar",
2078    "function (this:f): undefined");
2079    }
2080   
2081    /**
2082    * Tests the type of a function definition. The function defined by
2083    * {@code functionDef} should be named {@code "f"}.
2084    */
 
2085  42 toggle private void testFunctionType(String functionDef, String functionType)
2086    throws Exception {
2087  42 testFunctionType(functionDef, "f", functionType);
2088    }
2089   
2090    /**
2091    * Tests the type of a function definition. The function defined by
2092    * {@code functionDef} should be named {@code functionName}.
2093    */
 
2094  108 toggle private void testFunctionType(String functionDef, String functionName,
2095    String functionType) throws Exception {
2096    // using the variable initialization check to verify the function's type
2097  108 testTypes(
2098    functionDef +
2099    "/** @type number */var a=" + functionName + ";",
2100    "initializing variable\n" +
2101    "found : " + functionType + "\n" +
2102    "required: number");
2103    }
2104   
2105    /**
2106    * Tests the type of a function definition in externs.
2107    * The function defined by {@code functionDef} should be
2108    * named {@code functionName}.
2109    */
 
2110  3 toggle private void testExternFunctionType(String functionDef, String functionName,
2111    String functionType) throws Exception {
2112  3 testTypes(
2113    functionDef,
2114    "/** @type number */var a=" + functionName + ";",
2115    "initializing variable\n" +
2116    "found : " + functionType + "\n" +
2117    "required: number", false);
2118    }
2119   
 
2120  3 toggle public void testTypeRedefinition() throws Exception {
2121  3 testClosureTypesMultipleWarnings(
2122    "a={};/**@enum {string}*/ a.A = {ZOR:'b'};"
2123    + "/** @constructor */ a.A = function() {}",
2124    Lists.newArrayList(
2125    "variable a.A redefined with type function (new:a.A): undefined, " +
2126    "original definition at [testcode]:1 with type enum{a.A}",
2127    "assignment to property A of a\n" +
2128    "found : function (new:a.A): undefined\n" +
2129    "required: enum{a.A}"));
2130    }
2131   
 
2132  3 toggle public void testIn1() throws Exception {
2133  3 testTypes("'foo' in Object");
2134    }
2135   
 
2136  3 toggle public void testIn2() throws Exception {
2137  3 testTypes("3 in Object");
2138    }
2139   
 
2140  3 toggle public void testIn3() throws Exception {
2141  3 testTypes("undefined in Object");
2142    }
2143   
 
2144  3 toggle public void testIn4() throws Exception {
2145  3 testTypes("Date in Object",
2146    "left side of 'in'\n" +
2147    "found : function (new:Date, ?=, ?=, ?=, ?=, ?=, ?=, ?=): string\n" +
2148    "required: string");
2149    }
2150   
 
2151  3 toggle public void testIn5() throws Exception {
2152  3 testTypes("'x' in null",
2153    "'in' requires an object\n" +
2154    "found : null\n" +
2155    "required: Object");
2156    }
2157   
 
2158  3 toggle public void testIn6() throws Exception {
2159  3 testTypes(
2160    "/** @param {number} x */" +
2161    "function g(x) {}" +
2162    "g(1 in {});",
2163    "actual parameter 1 of g does not match formal parameter\n" +
2164    "found : boolean\n" +
2165    "required: number");
2166    }
2167   
 
2168  3 toggle public void testIn7() throws Exception {
2169    // Make sure we do inference in the 'in' expression.
2170  3 testTypes(
2171    "/**\n" +
2172    " * @param {number} x\n" +
2173    " * @return {number}\n" +
2174    " */\n" +
2175    "function g(x) { return 5; }" +
2176    "function f() {" +
2177    " var x = {};" +
2178    " x.foo = '3';" +
2179    " return g(x.foo) in {};" +
2180    "}",
2181    "actual parameter 1 of g does not match formal parameter\n" +
2182    "found : string\n" +
2183    "required: number");
2184    }
2185   
2186    // TODO(nicksantos): change this to something that makes sense.
2187    // public void testComparison1() throws Exception {
2188    // testTypes("/**@type null */var a;" +
2189    // "/**@type !Date */var b;" +
2190    // "if (a==b) {}",
2191    // "condition always evaluates to false\n" +
2192    // "left : null\n" +
2193    // "right: Date");
2194    // }
2195   
 
2196  3 toggle public void testComparison2() throws Exception {
2197  3 testTypes("/**@type number*/var a;" +
2198    "/**@type !Date */var b;" +
2199    "if (a!==b) {}",
2200    "condition always evaluates to true\n" +
2201    "left : number\n" +
2202    "right: Date");
2203    }
2204   
 
2205  3 toggle public void testComparison3() throws Exception {
2206    // Since null == undefined in JavaScript, this code is reasonable.
2207  3 testTypes("/** @type {(Object,undefined)} */var a;" +
2208    "var b = a == null");
2209    }
2210   
 
2211  3 toggle public void testComparison4() throws Exception {
2212  3 testTypes("/** @type {(!Object,undefined)} */var a;" +
2213    "/** @type {!Object} */var b;" +
2214    "var c = a == b");
2215    }
2216   
 
2217  3 toggle public void testComparison5() throws Exception {
2218  3 testTypes("/** @type null */var a;" +
2219    "/** @type null */var b;" +
2220    "a == b",
2221    "condition always evaluates to true\n" +
2222    "left : null\n" +
2223    "right: null");
2224    }
2225   
 
2226  3 toggle public void testComparison6() throws Exception {
2227  3 testTypes("/** @type null */var a;" +
2228    "/** @type null */var b;" +
2229    "a != b",
2230    "condition always evaluates to false\n" +
2231    "left : null\n" +
2232    "right: null");
2233    }
2234   
 
2235  3 toggle public void testComparison7() throws Exception {
2236  3 testTypes("var a;" +
2237    "var b;" +
2238    "a == b",
2239    "condition always evaluates to true\n" +
2240    "left : undefined\n" +
2241    "right: undefined");
2242    }
2243   
 
2244  3 toggle public void testComparison8() throws Exception {
2245  3 testTypes("/** @type {Array.<string>} */ var a = [];" +
2246    "a[0] == null || a[1] == undefined");
2247    }
2248   
 
2249  3 toggle public void testComparison9() throws Exception {
2250  3 testTypes("/** @type {Array.<undefined>} */ var a = [];" +
2251    "a[0] == null",
2252    "condition always evaluates to true\n" +
2253    "left : undefined\n" +
2254    "right: null");
2255    }
2256   
 
2257  3 toggle public void testComparison10() throws Exception {
2258  3 testTypes("/** @type {Array.<undefined>} */ var a = [];" +
2259    "a[0] === null");
2260    }
2261   
 
2262  3 toggle public void testEnumStaticMethod1() throws Exception {
2263  3 testTypes(
2264    "/** @enum */ var Foo = {AAA: 1};" +
2265    "/** @param {number} x */ Foo.method = function(x) {};" +
2266    "Foo.method(true);",
2267    "actual parameter 1 of Foo.method does not match formal parameter\n" +
2268    "found : boolean\n" +
2269    "required: number");
2270    }
2271   
 
2272  3 toggle public void testEnumStaticMethod2() throws Exception {
2273  3 testTypes(
2274    "/** @enum */ var Foo = {AAA: 1};" +
2275    "/** @param {number} x */ Foo.method = function(x) {};" +
2276    "function f() { Foo.method(true); }",
2277    "actual parameter 1 of Foo.method does not match formal parameter\n" +
2278    "found : boolean\n" +
2279    "required: number");
2280    }
2281   
 
2282  3 toggle public void testEnum1() throws Exception {
2283  3 testTypes("/**@enum*/var a={BB:1,CC:2};\n" +
2284    "/**@type {a}*/var d;d=a.BB;");
2285    }
2286   
 
2287  3 toggle public void testEnum2() throws Exception {
2288  3 testTypes("/**@enum*/var a={b:1}",
2289    "enum key b must be a syntactic constant");
2290    }
2291   
 
2292  3 toggle public void testEnum3() throws Exception {
2293  3 testTypes("/**@enum*/var a={BB:1,BB:2}",
2294    "variable a.BB redefined with type a.<number>, " +
2295    "original definition at [testcode]:1 with type a.<number>");
2296    }
2297   
 
2298  3 toggle public void testEnum4() throws Exception {
2299  3 testTypes("/**@enum*/var a={BB:'string'}",
2300    "assignment to property BB of enum{a}\n" +
2301    "found : string\n" +
2302    "required: number");
2303    }
2304   
 
2305  3 toggle public void testEnum5() throws Exception {
2306  3 testTypes("/**@enum {String}*/var a={BB:'string'}",
2307    "assignment to property BB of enum{a}\n" +
2308    "found : string\n" +
2309    "required: (String|null|undefined)");
2310    }
2311   
 
2312  3 toggle public void testEnum6() throws Exception {
2313  3 testTypes("/**@enum*/var a={BB:1,CC:2};\n/**@type {!Array}*/var d;d=a.BB;",
2314    "assignment\n" +
2315    "found : a.<number>\n" +
2316    "required: Array");
2317    }
2318   
 
2319  3 toggle public void testEnum7() throws Exception {
2320  3 testTypes("/** @enum */var a={AA:1,BB:2,CC:3};" +
2321    "/** @type a */var b=a.D;",
2322    "element D does not exist on this enum");
2323    }
2324   
 
2325  3 toggle public void testEnum8() throws Exception {
2326  3 testClosureTypesMultipleWarnings("/** @enum */var a=8;",
2327    Lists.newArrayList(
2328    "enum initializer must be an object literal or an enum",
2329    "initializing variable\n" +
2330    "found : number\n" +
2331    "required: enum{a}"));
2332    }
2333   
 
2334  3 toggle public void testEnum9() throws Exception {
2335  3 testClosureTypesMultipleWarnings(
2336    "var goog = {};" +
2337    "/** @enum */goog.a=8;",
2338    Lists.newArrayList(
2339    "assignment to property a of goog\n" +
2340    "found : number\n" +
2341    "required: enum{goog.a}",
2342    "enum initializer must be an object literal or an enum"));
2343    }
2344   
 
2345  3 toggle public void testEnum10() throws Exception {
2346  3 testTypes(
2347    "/** @enum {number} */" +
2348    "goog.K = { A : 3 };");
2349    }
2350   
 
2351  3 toggle public void testEnum11() throws Exception {
2352  3 testTypes(
2353    "/** @enum {number} */" +
2354    "goog.K = { 502 : 3 };");
2355    }
2356   
 
2357  3 toggle public void testEnum12() throws Exception {
2358  3 testTypes(
2359    "/** @enum {number} */ var a = {};" +
2360    "/** @enum */ var b = a;");
2361    }
2362   
 
2363  3 toggle public void testEnum13() throws Exception {
2364  3 testTypes(
2365    "/** @enum {number} */ var a = {};" +
2366    "/** @enum {string} */ var b = a;",
2367    "incompatible enum element types\n" +
2368    "found : number\n" +
2369    "required: string");
2370    }
2371   
 
2372  3 toggle public void testEnum14() throws Exception {
2373  3 testTypes(
2374    "/** @enum {number} */ var a = {FOO:5};" +
2375    "/** @enum */ var b = a;" +
2376    "var c = b.FOO;");
2377    }
2378   
 
2379  3 toggle public void testEnum15() throws Exception {
2380  3 testTypes(
2381    "/** @enum {number} */ var a = {FOO:5};" +
2382    "/** @enum */ var b = a;" +
2383    "var c = b.BAR;",
2384    "element BAR does not exist on this enum");
2385    }
2386   
 
2387  3 toggle public void testEnum16() throws Exception {
2388  3 testTypes("var goog = {};" +
2389    "/**@enum*/goog .a={BB:1,BB:2}",
2390    "variable goog.a.BB redefined with type goog.a.<number>, " +
2391    "original definition at [testcode]:1 with type goog.a.<number>");
2392    }
2393   
 
2394  3 toggle public void testEnum17() throws Exception {
2395  3 testTypes("var goog = {};" +
2396    "/**@enum*/goog.a={BB:'string'}",
2397    "assignment to property BB of enum{goog.a}\n" +
2398    "found : string\n" +
2399    "required: number");
2400    }
2401   
 
2402  3 toggle public void testEnum18() throws Exception {
2403  3 testTypes("/**@enum*/ var E = {A: 1, B: 2};" +
2404    "/** @param {!E} x\n@return {number} */\n" +
2405    "var f = function(x) { return x; };");
2406    }
2407   
 
2408  3 toggle public void testEnum19() throws Exception {
2409  3 testTypes("/**@enum*/ var E = {A: 1, B: 2};" +
2410    "/** @param {number} x\n@return {!E} */\n" +
2411    "var f = function(x) { return x; };",
2412    "inconsistent return type\n" +
2413    "found : number\n" +
2414    "required: E.<number>");
2415    }
2416   
 
2417  3 toggle public void testEnum20() throws Exception {
2418  3 testTypes("/**@enum*/ var E = {A: 1, B: 2}; var x = []; x[E.A] = 0;");
2419    }
2420   
 
2421  3 toggle public void testEnum21() throws Exception {
2422  3 Node n = parseAndTypeCheck(
2423    "/** @enum {string} */ var E = {A : 'a', B : 'b'};\n" +
2424    "/** @param {!E} x\n@return {!E} */ function f(x) { return x; }");
2425  3 Node nodeX = n.getLastChild().getLastChild().getLastChild().getLastChild();
2426  3 JSType typeE = nodeX.getJSType();
2427  3 assertFalse(typeE.isObject());
2428  3 assertFalse(typeE.isNullable());
2429    }
2430   
 
2431  3 toggle public void testEnum22() throws Exception {
2432  3 testTypes("/**@enum*/ var E = {A: 1, B: 2};" +
2433    "/** @param {E} x \n* @return {number} */ function f(x) {return x}");
2434    }
2435   
 
2436  3 toggle public void testEnum23() throws Exception {
2437  3 testTypes("/**@enum*/ var E = {A: 1, B: 2};" +
2438    "/** @param {E} x \n* @return {string} */ function f(x) {return x}",
2439    "inconsistent return type\n" +
2440    "found : E.<number>\n" +
2441    "required: string");
2442    }
2443   
 
2444  3 toggle public void testEnum24() throws Exception {
2445  3 testTypes("/**@enum {Object} */ var E = {A: {}};" +
2446    "/** @param {E} x \n* @return {!Object} */ function f(x) {return x}",
2447    "inconsistent return type\n" +
2448    "found : E.<(Object|null|undefined)>\n" +
2449    "required: Object");
2450    }
2451   
 
2452  3 toggle public void testEnum25() throws Exception {
2453  3 testTypes("/**@enum {!Object} */ var E = {A: {}};" +
2454    "/** @param {E} x \n* @return {!Object} */ function f(x) {return x}");
2455    }
2456   
 
2457  3 toggle public void testEnum26() throws Exception {
2458  3 testTypes("var a = {}; /**@enum*/ a.B = {A: 1, B: 2};" +
2459    "/** @param {a.B} x \n* @return {number} */ function f(x) {return x}");
2460    }
2461   
 
2462  3 toggle public void testEnum27() throws Exception {
2463    // x is unknown
2464  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2465    "function f(x) { return A == x; }");
2466    }
2467   
 
2468  3 toggle public void testEnum28() throws Exception {
2469    // x is unknown
2470  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2471    "function f(x) { return A.B == x; }");
2472    }
2473   
 
2474  3 toggle public void testEnum29() throws Exception {
2475  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2476    "/** @return {number} */ function f() { return A; }",
2477    "inconsistent return type\n" +
2478    "found : enum{A}\n" +
2479    "required: number");
2480    }
2481   
 
2482  3 toggle public void testEnum30() throws Exception {
2483  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2484    "/** @return {number} */ function f() { return A.B; }");
2485    }
2486   
 
2487  3 toggle public void testEnum31() throws Exception {
2488  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2489    "/** @return {A} */ function f() { return A; }",
2490    "inconsistent return type\n" +
2491    "found : enum{A}\n" +
2492    "required: A.<number>");
2493    }
2494   
 
2495  3 toggle public void testEnum32() throws Exception {
2496  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2497    "/** @return {A} */ function f() { return A.B; }");
2498    }
2499   
 
2500  3 toggle public void testEnum34() throws Exception {
2501  3 testTypes("/** @enum */ var A = {B: 1, C: 2}; " +
2502    "/** @param {number} x */ function f(x) { return x == A.B; }");
2503    }
2504   
 
2505  3 toggle public void testEnum35() throws Exception {
2506  3 testTypes("var a = a || {}; /** @enum */ a.b = {C: 1, D: 2};" +
2507    "/** @return {a.b} */ function f() { return a.b.C; }");
2508    }
2509   
 
2510  3 toggle public void testEnum36() throws Exception {
2511  3 testTypes("var a = a || {}; /** @enum */ a.b = {C: 1, D: 2};" +
2512    "/** @return {!a.b} */ function f() { return 1; }",
2513    "inconsistent return type\n" +
2514    "found : number\n" +
2515    "required: a.b.<number>");
2516    }
2517   
 
2518  3 toggle public void testEnum37() throws Exception {
2519  3 testTypes(
2520    "var goog = goog || {};" +
2521    "/** @enum {number} */ goog.a = {};" +
2522    "/** @enum */ var b = goog.a;");
2523    }
2524   
 
2525  3 toggle public void testEnum38() throws Exception {
2526  3 testTypes(
2527    "/** @enum {MyEnum} */ var MyEnum = {};" +
2528    "/** @param {MyEnum} x */ function f(x) {}",
2529    "Parse error. Cycle detected in inheritance chain " +
2530    "of type MyEnum");
2531    }
2532   
 
2533  3 toggle public void testEnum39() throws Exception {
2534  3 testTypes(
2535    "/** @enum {Number} */ var MyEnum = {FOO: new Number(1)};" +
2536    "/** @param {MyEnum} x \n * @return {number} */" +
2537    "function f(x) { return x == MyEnum.FOO && MyEnum.FOO == x; }",
2538    "inconsistent return type\n" +
2539    "found : boolean\n" +
2540    "required: number");
2541    }
2542   
 
2543  3 toggle public void testEnum40() throws Exception {
2544  3 testTypes(
2545    "/** @enum {Number} */ var MyEnum = {FOO: new Number(1)};" +
2546    "/** @param {number} x \n * @return {number} */" +
2547    "function f(x) { return x == MyEnum.FOO && MyEnum.FOO == x; }",
2548    "inconsistent return type\n" +
2549    "found : boolean\n" +
2550    "required: number");
2551    }
2552   
 
2553  3 toggle public void testAliasedEnum1() throws Exception {
2554  3 testTypes(
2555    "/** @enum */ var YourEnum = {FOO: 3};" +
2556    "/** @enum */ var MyEnum = YourEnum;" +
2557    "/** @param {MyEnum} x */ function f(x) {} f(MyEnum.FOO);");
2558    }
2559   
 
2560  3 toggle public void testAliasedEnum2() throws Exception {
2561  3 testTypes(
2562    "/** @enum */ var YourEnum = {FOO: 3};" +
2563    "/** @enum */ var MyEnum = YourEnum;" +
2564    "/** @param {YourEnum} x */ function f(x) {} f(MyEnum.FOO);");
2565    }
2566   
 
2567  3 toggle public void testAliasedEnum3() throws Exception {
2568  3 testTypes(
2569    "/** @enum */ var YourEnum = {FOO: 3};" +
2570    "/** @enum */ var MyEnum = YourEnum;" +
2571    "/** @param {MyEnum} x */ function f(x) {} f(YourEnum.FOO);");
2572    }
2573   
 
2574  3 toggle public void testAliasedEnum4() throws Exception {
2575  3 testTypes(
2576    "/** @enum */ var YourEnum = {FOO: 3};" +
2577    "/** @enum */ var MyEnum = YourEnum;" +
2578    "/** @param {YourEnum} x */ function f(x) {} f(YourEnum.FOO);");
2579    }
2580   
 
2581  3 toggle public void testAliasedEnum5() throws Exception {
2582  3 testTypes(
2583    "/** @enum */ var YourEnum = {FOO: 3};" +
2584    "/** @enum */ var MyEnum = YourEnum;" +
2585    "/** @param {string} x */ function f(x) {} f(MyEnum.FOO);",
2586    "actual parameter 1 of f does not match formal parameter\n" +
2587    "found : YourEnum.<number>\n" +
2588    "required: string");
2589    }
2590   
 
2591  3 toggle public void testBackwardsEnumUse1() throws Exception {
2592  3 testTypes(
2593    "/** @return {string} */ function f() { return MyEnum.FOO; }" +
2594    "/** @enum {string} */ var MyEnum = {FOO: 'x'};");
2595    }
2596   
 
2597  3 toggle public void testBackwardsEnumUse2() throws Exception {
2598  3 testTypes(
2599    "/** @return {number} */ function f() { return MyEnum.FOO; }" +
2600    "/** @enum {string} */ var MyEnum = {FOO: 'x'};",
2601    "inconsistent return type\n" +
2602    "found : MyEnum.<string>\n" +
2603    "required: number");
2604    }
2605   
 
2606  3 toggle public void testBackwardsEnumUse3() throws Exception {
2607  3 testTypes(
2608    "/** @return {string} */ function f() { return MyEnum.FOO; }" +
2609    "/** @enum {string} */ var YourEnum = {FOO: 'x'};" +
2610    "/** @enum {string} */ var MyEnum = YourEnum;");
2611    }
2612   
 
2613  3 toggle public void testBackwardsEnumUse4() throws Exception {
2614  3 testTypes(
2615    "/** @return {number} */ function f() { return MyEnum.FOO; }" +
2616    "/** @enum {string} */ var YourEnum = {FOO: 'x'};" +
2617    "/** @enum {string} */ var MyEnum = YourEnum;",
2618    "inconsistent return type\n" +
2619    "found : YourEnum.<string>\n" +
2620    "required: number");
2621    }
2622   
 
2623  3 toggle public void testBackwardsEnumUse5() throws Exception {
2624  3 testTypes(
2625    "/** @return {string} */ function f() { return MyEnum.BAR; }" +
2626    "/** @enum {string} */ var YourEnum = {FOO: 'x'};" +
2627    "/** @enum {string} */ var MyEnum = YourEnum;",
2628    "element BAR does not exist on this enum");
2629    }
2630   
 
2631  3 toggle public void testBackwardsConstructor1() throws Exception {
2632  3 testTypes(
2633    "function f() { (new Foo(true)); }" +
2634    "/** \n * @constructor \n * @param {number} x */" +
2635    "var Foo = function(x) {};",
2636    "actual parameter 1 of Foo does not match formal parameter\n" +
2637    "found : boolean\n" +
2638    "required: number");
2639    }
2640   
 
2641  3 toggle public void testBackwardsConstructor2() throws Exception {
2642  3 testTypes(
2643    "function f() { (new Foo(true)); }" +
2644    "/** \n * @constructor \n * @param {number} x */" +
2645    "var YourFoo = function(x) {};" +
2646    "/** \n * @constructor \n * @param {number} x */" +
2647    "var Foo = YourFoo;",
2648    "actual parameter 1 of Foo does not match formal parameter\n" +
2649    "found : boolean\n" +
2650    "required: number");
2651    }
2652   
 
2653  3 toggle public void testMinimalConstructorAnnotation() throws Exception {
2654  3 testTypes("/** @constructor */function Foo(){}");
2655    }
2656   
 
2657  3 toggle public void testGoodExtends1() throws Exception {
2658    // A minimal @extends example
2659  3 testTypes("/** @constructor */function base() {}\n" +
2660    "/** @constructor\n * @extends {base} */function derived() {}\n");
2661    }
2662   
 
2663  3 toggle public void testGoodExtends2() throws Exception {
2664  3 testTypes("/** @constructor\n * @extends base */function derived() {}\n" +
2665    "/** @constructor */function base() {}\n");
2666    }
2667   
 
2668  3 toggle public void testGoodExtends3() throws Exception {
2669  3 testTypes("/** @constructor\n * @extends {Object} */function base() {}\n" +
2670    "/** @constructor\n * @extends {base} */function derived() {}\n");
2671    }
2672   
 
2673  3 toggle public void testGoodExtends4() throws Exception {
2674    // Ensure that @extends actually sets the base type of a constructor
2675    // correctly. Because this isn't part of the human-readable Function
2676    // definition, we need to crawl the prototype chain (eww).
2677  3 Node n = parseAndTypeCheck(
2678    "var goog = {};\n" +
2679    "/** @constructor */goog.Base = function(){};\n" +
2680    "/** @constructor\n" +
2681    " * @extends {goog.Base} */goog.Derived = function(){};\n");
2682  3 Node subTypeName = n.getLastChild().getLastChild().getFirstChild();
2683  3 assertEquals("goog.Derived", subTypeName.getQualifiedName());
2684   
2685  3 FunctionType subCtorType =
2686    (FunctionType) subTypeName.getNext().getJSType();
2687  3 assertEquals("goog.Derived", subCtorType.getInstanceType().toString());
2688   
2689  3 JSType superType = subCtorType.getPrototype().getImplicitPrototype();
2690  3 assertEquals("goog.Base", superType.toString());
2691    }
2692   
 
2693  3 toggle public void testGoodExtends5() throws Exception {
2694    // we allow for the extends annotation to be placed first
2695  3 testTypes("/** @constructor */function base() {}\n" +
2696    "/** @extends {base}\n * @constructor */function derived() {}\n");
2697    }
2698   
 
2699  3 toggle public void testGoodExtends6() throws Exception {
2700  3 testFunctionType(
2701    CLOSURE_DEFS +
2702    "/** @constructor */function base() {}\n" +
2703    "/** @return {number} */ " +
2704    " base.prototype.foo = function() { return 1; };\n" +
2705    "/** @extends {base}\n * @constructor */function derived() {}\n" +
2706    "goog.inherits(derived, base);",
2707    "derived.superClass_.foo",
2708    "function (this:base): number");
2709    }
2710   
 
2711  3 toggle public void testGoodExtends7() throws Exception {
2712  3 testFunctionType(
2713    "Function.prototype.inherits = function(x) {};" +
2714    "/** @constructor */function base() {}\n" +
2715    "/** @extends {base}\n * @constructor */function derived() {}\n" +
2716    "derived.inherits(base);",
2717    "(new derived).constructor",
2718    "function (new:derived, ...[?]): ?");
2719    }
2720   
 
2721  3 toggle public void testGoodExtends8() throws Exception {
2722  3 testTypes("/** @constructor \n @extends {Base} */ function Sub() {}" +
2723    "/** @return {number} */ function f() { return (new Sub()).foo; }" +
2724    "/** @constructor */ function Base() {}" +
2725    "/** @type {boolean} */ Base.prototype.foo = true;",
2726    "inconsistent return type\n" +
2727    "found : boolean\n" +
2728    "required: number");
2729    }
2730   
 
2731  3 toggle public void testGoodExtends9() throws Exception {
2732  3 testTypes(
2733    "/** @constructor */ function Super() {}" +
2734    "Super.prototype.foo = function() {};" +
2735    "/** @constructor \n * @extends {Super} */ function Sub() {}" +
2736    "Sub.prototype = new Super();" +
2737    "/** @override */ Sub.prototype.foo = function() {};");
2738    }
2739   
 
2740  3 toggle public void testGoodExtends10() throws Exception {
2741  3 testTypes(
2742    "/** @constructor */ function Super() {}" +
2743    "/** @constructor \n * @extends {Super} */ function Sub() {}" +
2744    "Sub.prototype = new Super();" +
2745    "/** @return {Super} */ function foo() { return new Sub(); }");
2746    }
2747   
 
2748  3 toggle public void testGoodExtends11() throws Exception {
2749  3 testTypes(
2750    "/** @constructor */ function Super() {}" +
2751    "/** @param {boolean} x */ Super.prototype.foo = function(x) {};" +
2752    "/** @constructor \n * @extends {Super} */ function Sub() {}" +
2753    "Sub.prototype = new Super();" +
2754    "(new Sub()).foo(0);",
2755    "actual parameter 1 of Super.prototype.foo " +
2756    "does not match formal parameter\n" +
2757    "found : number\n" +
2758    "required: boolean");
2759    }
2760   
 
2761  3 toggle public void testBadExtends1() throws Exception {
2762  3 testTypes("/** @constructor */function base() {}\n" +
2763    "/** @constructor\n * @extends {not_base} */function derived() {}\n",
2764    "Bad type annotation. Unknown type not_base");
2765    }
2766   
 
2767  3 toggle public void testBadExtends2() throws Exception {
2768  3 testTypes("/** @constructor */function base() {\n" +
2769    "/** @type {!Number}*/\n" +
2770    "this.baseMember = new Number(4);\n" +
2771    "}\n" +
2772    "/** @constructor\n" +
2773    " * @extends {base} */function derived() {}\n" +
2774    "/** @param {!String} x*/\n" +
2775    "function foo(x){ }\n" +
2776    "/** @type {!derived}*/var y;\n" +
2777    "foo(y.baseMember);\n",
2778    "actual parameter 1 of foo does not match formal parameter\n" +
2779    "found : Number\n" +
2780    "required: String");
2781    }
2782   
 
2783  3 toggle public void testBadExtends3() throws Exception {
2784  3 testTypes("/** @extends {Object} */function base() {}",
2785    "@extends used without @constructor or @interface for base");
2786    }
2787   
 
2788  3 toggle public void testLateExtends() throws Exception {
2789  3 testTypes(
2790    CLOSURE_DEFS +
2791    "/** @constructor */ function Foo() {}\n" +
2792    "Foo.prototype.foo = function() {};\n" +
2793    "/** @constructor */function Bar() {}\n" +
2794    "goog.inherits(Foo, Bar);\n",
2795    "Missing @extends tag on type Foo");
2796    }
2797   
 
2798  3 toggle public void testSuperclassMatch() throws Exception {
2799  3 compiler.getOptions().setCodingConvention(new GoogleCodingConvention());
2800  3 testTypes("/** @constructor */ var Foo = function() {};\n" +
2801    "/** @constructor \n @extends Foo */ var Bar = function() {};\n" +
2802    "Bar.inherits = function(x){};" +
2803    "Bar.inherits(Foo);\n");
2804    }
2805   
 
2806  3 toggle public void testSuperclassMatchWithMixin() throws Exception {
2807  3 compiler.getOptions().setCodingConvention(new GoogleCodingConvention());
2808  3 testTypes("/** @constructor */ var Foo = function() {};\n" +
2809    "/** @constructor */ var Baz = function() {};\n" +
2810    "/** @constructor \n @extends Foo */ var Bar = function() {};\n" +
2811    "Bar.inherits = function(x){};" +
2812    "Bar.mixin = function(y){};" +
2813    "Bar.inherits(Foo);\n" +
2814    "Bar.mixin(Baz);\n");
2815    }
2816   
 
2817  3 toggle public void testSuperclassMismatch1() throws Exception {
2818  3 compiler.getOptions().setCodingConvention(new GoogleCodingConvention());
2819  3 testTypes("/** @constructor */ var Foo = function() {};\n" +
2820    "/** @constructor \n @extends Object */ var Bar = function() {};\n" +
2821    "Bar.inherits = function(x){};" +
2822    "Bar.inherits(Foo);\n",
2823    "Missing @extends tag on type Bar");
2824    }
2825   
 
2826  3 toggle public void testSuperclassMismatch2() throws Exception {
2827  3 compiler.getOptions().setCodingConvention(new GoogleCodingConvention());
2828  3 testTypes("/** @constructor */ var Foo = function(){};\n" +
2829    "/** @constructor */ var Bar = function(){};\n" +
2830    "Bar.inherits = function(x){};" +
2831    "Bar.inherits(Foo);",
2832    "Missing @extends tag on type Bar");
2833    }
2834   
 
2835  3 toggle public void testSuperClassDefinedAfterSubClass1() throws Exception {
2836  3 testTypes(
2837    "/** @constructor \n * @extends {Base} */ function A() {}" +
2838    "/** @constructor \n * @extends {Base} */ function B() {}" +
2839    "/** @constructor */ function Base() {}" +
2840    "/** @param {A|B} x \n * @return {B|A} */ " +
2841    "function foo(x) { return x; }");
2842    }
2843   
 
2844  3 toggle public void testSuperClassDefinedAfterSubClass2() throws Exception {
2845  3 testTypes(
2846    "/** @constructor \n * @extends {Base} */ function A() {}" +
2847    "/** @constructor \n * @extends {Base} */ function B() {}" +
2848    "/** @param {A|B} x \n * @return {B|A} */ " +
2849    "function foo(x) { return x; }" +
2850    "/** @constructor */ function Base() {}");
2851    }
2852   
 
2853  3 toggle public void testDirectPrototypeAssignment1() throws Exception {
2854  3 testTypes(
2855    "/** @constructor */ function Base() {}" +
2856    "Base.prototype.foo = 3;" +
2857    "/** @constructor \n * @extends {Base} */ function A() {}" +
2858    "A.prototype = new Base();" +
2859    "/** @return {string} */ function foo() { return (new A).foo; }",
2860    "inconsistent return type\n" +
2861    "found : number\n" +
2862    "required: string");
2863    }
2864   
 
2865  3 toggle public void testDirectPrototypeAssignment2() throws Exception {
2866    // This ensures that we don't attach property 'foo' onto the Base
2867    // instance object.
2868  3 testTypes(
2869    "/** @constructor */ function Base() {}" +
2870    "/** @constructor \n * @extends {Base} */ function A() {}" +
2871    "A.prototype = new Base();" +
2872    "A.prototype.foo = 3;" +
2873    "/** @return {string} */ function foo() { return (new Base).foo; }");
2874    }
2875   
 
2876  3 toggle public void testGoodImplements1() throws Exception {
2877  3 testTypes("/** @interface */function Disposable() {}\n" +
2878    "/** @implements {Disposable}\n * @constructor */function f() {}");
2879    }
2880   
 
2881  3 toggle public void testGoodImplements2() throws Exception {
2882  3 testTypes("/** @interface */function Base1() {}\n" +
2883    "/** @interface */function Base2() {}\n" +
2884    "/** @constructor\n" +
2885    " * @implements {Base1}\n" +
2886    " * @implements {Base2}\n" +
2887    " */ function derived() {}");
2888    }
2889   
 
2890  3 toggle public void testBadImplements1() throws Exception {
2891  3 testTypes("/** @interface */function Base1() {}\n" +
2892    "/** @interface */function Base2() {}\n" +
2893    "/** @constructor\n" +
2894    " * @implements {nonExistent}\n" +
2895    " * @implements {Base2}\n" +
2896    " */ function derived() {}",
2897    "Bad type annotation. Unknown type nonExistent");
2898    }
2899   
 
2900  3 toggle public void testBadImplements2() throws Exception {
2901  3 testTypes("/** @interface */function Disposable() {}\n" +
2902    "/** @implements {Disposable}\n */function f() {}",
2903    "@implements used without @constructor for f");
2904    }
2905   
 
2906  3 toggle public void testBadImplements3() throws Exception {
2907  3 testTypes("/** @interface */function Disposable() {}\n" +
2908    "/** @implements {Disposable}\n * @interface */function f() {}",
2909    "f cannot implement this type; an interface can only extend, " +
2910    "but not implement interfaces");
2911    }
2912   
 
2913  3 toggle public void testInterfaceExtends() throws Exception {
2914  3 testTypes("/** @interface */function A() {}\n" +
2915    "/** @interface \n * @extends {A} */function B() {}\n" +
2916    "/** @constructor\n" +
2917    " * @implements {B}\n" +
2918    " */ function derived() {}");
2919    }
2920   
 
2921  3 toggle public void testBadInterfaceExtends1() throws Exception {
2922  3 testTypes("/** @interface \n * @extends {nonExistent} */function A() {}",
2923    "Bad type annotation. Unknown type nonExistent");
2924    }
2925   
 
2926  3 toggle public void testBadInterfaceExtends2() throws Exception {
2927  3 testTypes("/** @constructor */function A() {}\n" +
2928    "/** @interface \n * @extends {A} */function B() {}",
2929    "B cannot extend this type; interfaces can only extend interfaces");
2930    }
2931   
 
2932  3 toggle public void testBadInterfaceExtends3() throws Exception {
2933  3 testTypes("/** @interface */function A() {}\n" +
2934    "/** @constructor \n * @extends {A} */function B() {}",
2935    "B cannot extend this type; constructors can only extend constructors");
2936    }
2937   
 
2938  3 toggle public void testBadInterfaceExtends4() throws Exception {
2939    // TODO(user): This should be detected as an error. Even if we enforce
2940    // that A cannot be used in the assignment, we should still detect the
2941    // inheritance chain as invalid.
2942  3 testTypes("/** @interface */function A() {}\n" +
2943    "/** @constructor */function B() {}\n" +
2944    "B.prototype = A;");
2945    }
2946   
 
2947  3 toggle public void testBadInterfaceExtends5() throws Exception {
2948    // TODO(user): This should be detected as an error. Even if we enforce
2949    // that A cannot be used in the assignment, we should still detect the
2950    // inheritance chain as invalid.
2951  3 testTypes("/** @constructor */function A() {}\n" +
2952    "/** @interface */function B() {}\n" +
2953    "B.prototype = A;");
2954    }
2955   
 
2956  3 toggle public void testBadImplementsAConstructor() throws Exception {
2957  3 testTypes("/** @constructor */function A() {}\n" +
2958    "/** @constructor \n * @implements {A} */function B() {}",
2959    "can only implement interfaces");
2960    }
2961   
 
2962  3 toggle public void testBadImplementsNonInterfaceType() throws Exception {
2963  3 testTypes("/** @constructor \n * @implements {Boolean} */function B() {}",
2964    "can only implement interfaces");
2965    }
2966   
 
2967  3 toggle public void testBadImplementsNonObjectType() throws Exception {
2968  3 testTypes("/** @constructor \n * @implements {string} */function S() {}",
2969    "can only implement interfaces");
2970    }
2971   
 
2972  3 toggle public void testInterfaceAssignment1() throws Exception {
2973  3 testTypes("/** @interface */var I = function() {};\n" +
2974    "/** @constructor\n@implements {I} */var T = function() {};\n" +
2975    "var t = new T();\n" +
2976    "/** @type {!I} */var i = t;");
2977    }
2978   
 
2979  3 toggle public void testInterfaceAssignment2() throws Exception {
2980  3 testTypes("/** @interface */var I = function() {};\n" +
2981    "/** @constructor */var T = function() {};\n" +
2982    "var t = new T();\n" +
2983    "/** @type {!I} */var i = t;",
2984    "initializing variable\n" +
2985    "found : T\n" +
2986    "required: I");
2987    }
2988   
 
2989  3 toggle public void testInterfaceAssignment3() throws Exception {
2990  3 testTypes("/** @interface */var I = function() {};\n" +
2991    "/** @constructor\n@implements {I} */var T = function() {};\n" +
2992    "var t = new T();\n" +
2993    "/** @type {I|number} */var i = t;");
2994    }
2995   
 
2996  3 toggle public void testInterfaceAssignment4() throws Exception {
2997  3 testTypes("/** @interface */var I1 = function() {};\n" +
2998    "/** @interface */var I2 = function() {};\n" +
2999    "/** @constructor\n@implements {I1} */var T = function() {};\n" +
3000    "var t = new T();\n" +
3001    "/** @type {I1|I2} */var i = t;");
3002    }
3003   
 
3004  3 toggle public void testInterfaceAssignment5() throws Exception {
3005  3 testTypes("/** @interface */var I1 = function() {};\n" +
3006    "/** @interface */var I2 = function() {};\n" +
3007    "/** @constructor\n@implements {I1}\n@implements {I2}*/" +
3008    "var T = function() {};\n" +
3009    "var t = new T();\n" +
3010    "/** @type {I1} */var i1 = t;\n" +
3011    "/** @type {I2} */var i2 = t;\n");
3012    }
3013   
 
3014  3 toggle public void testInterfaceAssignment6() throws Exception {
3015  3 testTypes("/** @interface */var I1 = function() {};\n" +
3016    "/** @interface */var I2 = function() {};\n" +
3017    "/** @constructor\n@implements {I1} */var T = function() {};\n" +
3018    "/** @type {!I1} */var i1 = new T();\n" +
3019    "/** @type {!I2} */var i2 = i1;\n",
3020    "initializing variable\n" +
3021    "found : I1\n" +
3022    "required: I2");
3023    }
3024   
 
3025  3 toggle public void testInterfaceAssignment7() throws Exception {
3026  3 testTypes("/** @interface */var I1 = function() {};\n" +
3027    "/** @interface\n@extends {I1}*/var I2 = function() {};\n" +
3028    "/** @constructor\n@implements {I2}*/var T = function() {};\n" +
3029    "var t = new T();\n" +
3030    "/** @type {I1} */var i1 = t;\n" +
3031    "/** @type {I2} */var i2 = t;\n" +
3032    "i1 = i2;\n");
3033    }
3034   
 
3035  3 toggle public void testInterfaceAssignment8() throws Exception {
3036  3 testTypes("/** @interface */var I = function() {};\n" +
3037    "/** @type {I} */var i;\n" +
3038    "/** @type {Object} */var o = i;");
3039    }
3040   
 
3041  3 toggle public void testInterfaceAssignment9() throws Exception {
3042  3 testTypes("/** @interface */var I = function() {};\n" +
3043    "/** @return {I?} */function f() { return null; }\n" +
3044    "/** @type {!I} */var i = f();\n",
3045    "initializing variable\n" +
3046    "found : (I|null|undefined)\n" +
3047    "required: I");
3048    }
3049   
 
3050  3 toggle public void testInterfaceAssignment10() throws Exception {
3051  3 testTypes("/** @interface */var I1 = function() {};\n" +
3052    "/** @interface */var I2 = function() {};\n" +
3053    "/** @constructor\n@implements {I2} */var T = function() {};\n" +
3054    "/** @return {!I1|!I2} */function f() { return new T(); }\n" +
3055    "/** @type {!I1} */var i1 = f();\n",
3056    "initializing variable\n" +
3057    "found : (I1|I2)\n" +
3058    "required: I1");
3059    }
3060   
 
3061  3 toggle public void testInterfaceAssignment11() throws Exception {
3062  3 testTypes("/** @interface */var I1 = function() {};\n" +
3063    "/** @interface */var I2 = function() {};\n" +
3064    "/** @constructor */var T = function() {};\n" +
3065    "/** @return {!I1|!I2|!T} */function f() { return new T(); }\n" +
3066    "/** @type {!I1} */var i1 = f();\n",
3067    "initializing variable\n" +
3068    "found : (I1|I2|T)\n" +
3069    "required: I1");
3070    }
3071   
 
3072  3 toggle public void testInterfaceAssignment12() throws Exception {
3073  3 testTypes("/** @interface */var I = function() {};\n" +
3074    "/** @constructor\n@implements{I}*/var T1 = function() {};\n" +
3075    "/** @constructor\n@extends {T1}*/var T2 = function() {};\n" +
3076    "/** @return {I} */function f() { return new T2(); }");
3077    }
3078   
 
3079  3 toggle public void testInterfaceAssignment13() throws Exception {
3080  3 testTypes("/** @interface */var I = function() {};\n" +
3081    "/** @constructor\n@implements {I}*/var T = function() {};\n" +
3082    "/** @constructor */function Super() {};\n" +
3083    "/** @return {I} */Super.prototype.foo = " +
3084    "function() { return new T(); };\n" +
3085    "/** @constructor\n@extends {Super} */function Sub() {}\n" +
3086    "/** @override\n@return {T} */Sub.prototype.foo = " +
3087    "function() { return new T(); };\n");
3088    }
3089   
 
3090  3 toggle public void testGetprop1() throws Exception {
3091  3 testTypes("/** @return {void}*/function foo(){foo().bar;}",
3092    "No properties on this expression\n" +
3093    "found : undefined\n" +
3094    "required: Object");
3095    }
3096   
 
3097  3 toggle public void testArrayAccess1() throws Exception {
3098  3 testTypes("var a = []; var b = a['hi'];");
3099    }
3100   
 
3101  3 toggle public void testArrayAccess2() throws Exception {
3102  3 testTypes("var a = []; var b = a[[1,2]];",
3103    "array access\n" +
3104    "found : Array\n" +
3105    "required: number");
3106    }
3107   
 
3108  3 toggle public void testArrayAccess3() throws Exception {
3109  3 testTypes("var bar = [];" +
3110    "/** @return {void} */function baz(){};" +
3111    "var foo = bar[baz()];",
3112    "array access\n" +
3113    "found : undefined\n" +
3114    "required: number");
3115    }
3116   
 
3117  3 toggle public void testArrayAccess4() throws Exception {
3118  3 testTypes("/**@return {!Array}*/function foo(){};var bar = foo()[foo()];",
3119    "array access\n" +
3120    "found : Array\n" +
3121    "required: number");
3122    }
3123   
 
3124  3 toggle public void testArrayAccess6() throws Exception {
3125  3 testTypes("var bar = null[1];",
3126    "only arrays or objects can be accessed\n" +
3127    "found : null\n" +
3128    "required: Object");
3129    }
3130   
 
3131  3 toggle public void testArrayAccess7() throws Exception {
3132  3 testTypes("var bar = void 0; bar[0];",
3133    "only arrays or objects can be accessed\n" +
3134    "found : undefined\n" +
3135    "required: Object");
3136    }
3137   
 
3138  3 toggle public void testArrayAccess8() throws Exception {
3139    // Verifies that we don't emit two warnings, because
3140    // the var has been dereferenced after the first one.
3141  3 testTypes("var bar = void 0; bar[0]; bar[1];",
3142    "only arrays or objects can be accessed\n" +
3143    "found : undefined\n" +
3144    "required: Object");
3145    }
3146   
 
3147  3 toggle public void testPropAccess() throws Exception {
3148  3 testTypes("/** @param {*} x */var f = function(x) {\n" +
3149    "var o = String(x);\n" +
3150    "if (typeof o['a'] != 'undefined') { return o['a']; }\n" +
3151    "return null;\n" +
3152    "};");
3153    }
3154   
 
3155  3 toggle public void testPropAccess2() throws Exception {
3156  3 testTypes("var bar = void 0; bar.baz;",
3157    "No properties on this expression\n" +
3158    "found : undefined\n" +
3159    "required: Object");
3160    }
3161   
 
3162  3 toggle public void testPropAccess3() throws Exception {
3163    // Verifies that we don't emit two warnings, because
3164    // the var has been dereferenced after the first one.
3165  3 testTypes("var bar = void 0; bar.baz; bar.bax;",
3166    "No properties on this expression\n" +
3167    "found : undefined\n" +
3168    "required: Object");
3169    }
3170   
 
3171  3 toggle public void testPropAccess4() throws Exception {
3172  3 testTypes("/** @param {*} x */ function f(x) { return x['hi']; }");
3173    }
3174   
 
3175  3 toggle public void testSwitchCase1() throws Exception {
3176  3 testTypes("/**@type number*/var a;" +
3177    "/**@type string*/var b;" +
3178    "switch(a){case b:;}",
3179    "case expression doesn't match switch\n" +
3180    "found : string\n" +
3181    "required: number");
3182    }
3183   
 
3184  3 toggle public void testSwitchCase2() throws Exception {
3185  3 testTypes("var a = null; switch (typeof a) { case 'foo': }");
3186    }
3187   
 
3188  3 toggle public void testVar1() throws Exception {
3189  3 TypeCheckResult p =
3190    parseAndTypeCheckWithScope("/** @type {(string,null)} */var a = null");
3191   
3192  3 assertTypeEquals(createUnionType(STRING_TYPE, NULL_TYPE),
3193    p.scope.getVar("a").getType());
3194    }
3195   
 
3196  3 toggle public void testVar2() throws Exception {
3197  3 testTypes("/** @type {Function} */ var a = function(){}");
3198    }
3199   
 
3200  3 toggle public void testVar3() throws Exception {
3201  3 TypeCheckResult p = parseAndTypeCheckWithScope("var a = 3;");
3202   
3203  3 assertTypeEquals(NUMBER_TYPE, p.scope.getVar("a").getType());
3204    }
3205   
 
3206  3 toggle public void testVar4() throws Exception {
3207  3 TypeCheckResult p = parseAndTypeCheckWithScope(
3208    "var a = 3; a = 'string';");
3209   
3210  3 assertTypeEquals(createUnionType(STRING_TYPE, NUMBER_TYPE),
3211    p.scope.getVar("a").getType());
3212    }
3213   
 
3214  3 toggle public void testVar5() throws Exception {
3215  3 testTypes("var goog = {};" +
3216    "/** @type string */goog.foo = 'hello';" +
3217    "/** @type number */var a = goog.foo;",
3218    "initializing variable\n" +
3219    "found : string\n" +
3220    "required: number");
3221    }
3222   
 
3223  3 toggle public void testVar6() throws Exception {
3224  3 testTypes(
3225    "function f() {" +
3226    " return function() {" +
3227    " /** @type {!Date} */" +
3228    " var a = 7;" +
3229    " };" +
3230    "}",
3231    "initializing variable\n" +
3232    "found : number\n" +
3233    "required: Date");
3234    }
3235   
 
3236  3 toggle public void testVar7() throws Exception {
3237  3 testTypes("/** @type number */var a, b;",
3238    "declaration of multiple variables with shared type information");
3239    }
3240   
 
3241  3 toggle public void testVar8() throws Exception {
3242  3 testTypes("var a, b;");
3243    }
3244   
 
3245  3 toggle public void testVar9() throws Exception {
3246  3 testTypes("/** @enum */var a;",
3247    "enum initializer must be an object literal or an enum");
3248    }
3249   
 
3250  3 toggle public void testVar10() throws Exception {
3251  3 testTypes("/** @type !Number */var foo = 'abc';",
3252    "initializing variable\n" +
3253    "found : string\n" +
3254    "required: Number");
3255    }
3256   
 
3257  3 toggle public void testVar11() throws Exception {
3258  3 testTypes("var /** @type !Date */foo = 'abc';",
3259    "initializing variable\n" +
3260    "found : string\n" +
3261    "required: Date");
3262    }
3263   
 
3264  3 toggle public void testVar12() throws Exception {
3265  3 testTypes("var /** @type !Date */foo = 'abc', " +
3266    "/** @type !RegExp */bar = 5;",
3267    new String[] {
3268    "initializing variable\n" +
3269    "found : string\n" +
3270    "required: Date",
3271    "initializing variable\n" +
3272    "found : number\n" +
3273    "required: RegExp"});
3274    }
3275   
 
3276  3 toggle public void testVar13() throws Exception {
3277    // this caused an NPE
3278  3 testTypes("var /** @type number */a,a;");
3279    }
3280   
 
3281  3 toggle public void testVar14() throws Exception {
3282  3 testTypes("/** @return {number} */ function f() { var x; return x; }",
3283    "inconsistent return type\n" +
3284    "found : undefined\n" +
3285    "required: number");
3286    }
3287   
 
3288  3 toggle public void testVar15() throws Exception {
3289  3 testTypes("/** @return {number} */" +
3290    "function f() { var x = x || {}; return x; }",
3291    "inconsistent return type\n" +
3292    "found : {}\n" +
3293    "required: number");
3294    }
3295   
 
3296  3 toggle public void testAssign1() throws Exception {
3297  3 testTypes("var goog = {};" +
3298    "/** @type number */goog.foo = 'hello';",
3299    "assignment to property foo of goog\n" +
3300    "found : string\n" +
3301    "required: number");
3302    }
3303   
 
3304  3 toggle public void testAssign2() throws Exception {
3305  3 testTypes("var goog = {};" +
3306    "/** @type number */goog.foo = 3;" +
3307    "goog.foo = 'hello';",
3308    "assignment to property foo of goog\n" +
3309    "found : string\n" +
3310    "required: number");
3311    }
3312   
 
3313  3 toggle public void testAssign3() throws Exception {
3314  3 testTypes("var goog = {};" +
3315    "/** @type number */goog.foo = 3;" +
3316    "goog.foo = 4;");
3317    }
3318   
 
3319  3 toggle public void testAssign4() throws Exception {
3320  3 testTypes("var goog = {};" +
3321    "goog.foo = 3;" +
3322    "goog.foo = 'hello';");
3323    }
3324   
 
3325  3 toggle public void testAssignInference() throws Exception {
3326  3 testTypes(
3327    "/**" +
3328    " * @param {Array} x" +
3329    " * @return {number}" +
3330    " */" +
3331    "function f(x) {" +
3332    " var y = null;" +
3333    " y = x[0];" +
3334    " if (y == null) { return 4; } else { return 6; }" +
3335    "}");
3336    }
3337   
 
3338  3 toggle public void testOr1() throws Exception {
3339  3 testTypes("/** @type number */var a;" +
3340    "/** @type number */var b;" +
3341    "a + b || undefined;");
3342    }
3343   
 
3344  3 toggle public void testOr2() throws Exception {
3345  3 testTypes("/** @type number */var a;" +
3346    "/** @type number */var b;" +
3347    "/** @type number */var c = a + b || undefined;",
3348    "initializing variable\n" +
3349    "found : (number|undefined)\n" +
3350    "required: number");
3351    }
3352   
 
3353  3 toggle public void testOr3() throws Exception {
3354  3 testTypes("/** @type {(number, undefined)} */var a;" +
3355    "/** @type number */var c = a || 3;");
3356    }
3357   
3358    /**
3359    * Test that type inference continues with the right side,
3360    * when no short-circuiting is possible.
3361    * See bugid 1205387 for more details.
3362    */
 
3363  3 toggle public void testOr4() throws Exception {
3364  3 testTypes("/**@type {number} */var x;x=null || \"a\";",
3365    "assignment\n" +
3366    "found : string\n" +
3367    "required: number");
3368    }
3369   
3370    /**
3371    * @see #testOr4()
3372    */
 
3373  3 toggle public void testOr5() throws Exception {
3374  3 testTypes("/**@type {number} */var x;x=undefined || \"a\";",
3375    "assignment\n" +
3376    "found : string\n" +
3377    "required: number");
3378    }
3379   
 
3380  3 toggle public void testAnd1() throws Exception {
3381  3 testTypes("/** @type number */var a;" +
3382    "/** @type number */var b;" +
3383    "a + b && undefined;");
3384    }
3385   
 
3386  3 toggle public void testAnd2() throws Exception {
3387  3 testTypes("/** @type number */var a;" +
3388    "/** @type number */var b;" +
3389    "/** @type number */var c = a + b && undefined;",
3390    "initializing variable\n" +
3391    "found : (number|undefined)\n" +
3392    "required: number");
3393    }
3394   
 
3395  3 toggle public void testAnd3() throws Exception {
3396  3 testTypes("/** @type {(!Array, undefined)} */var a;" +
3397    "/** @type number */var c = a && undefined;",
3398    "initializing variable\n" +
3399    "found : undefined\n" +
3400    "required: number");
3401    }
3402   
 
3403  3 toggle public void testAnd4() throws Exception {
3404  3 testTypes("/** @param {number} x */function f(x){};\n" +
3405    "/** @type null */var x; /** @type {number?} */var y;\n" +
3406    "if (x && y) { f(y) }");
3407    }
3408   
 
3409  3 toggle public void testAnd5() throws Exception {
3410  3 testTypes("/** @param {number} x\n@param {string} y*/function f(x,y){};\n" +
3411    "/** @type {number?} */var x; /** @type {string?} */var y;\n" +
3412    "if (x && y) { f(x, y) }");
3413    }
3414   
 
3415  3 toggle public void testAnd6() throws Exception {
3416  3 testTypes("/** @param {number} x */function f(x){};\n" +
3417    "/** @type {number|undefined} */var x;\n" +
3418    "if (x && f(x)) { f(x) }");
3419    }
3420   
 
3421  3 toggle public void testAnd7() throws Exception {
3422    // TODO(user): a deterministic warning should be generated for this
3423    // case since x && x is always false. The implementation of this requires
3424    // a more precise handling of a null value within a variable's type.
3425    // Currently, a null value defaults to ? which passes every check.
3426  3 testTypes("/** @type null */var x; if (x && x) {}");
3427    }
3428   
 
3429  3 toggle public void testHook() throws Exception {
3430  3 testTypes("/**@return {void}*/function foo(){ var x=foo()?a:b; }");
3431    }
3432   
 
3433  3 toggle public void testHookRestrictsType1() throws Exception {
3434  3 testTypes("/** @return {(string,null)} */" +
3435    "function f() { return null;}" +
3436    "/** @type {(string,null)} */ var a = f();" +
3437    "/** @type string */" +
3438    "var b = a ? a : 'default';");
3439    }
3440   
 
3441  3 toggle public void testHookRestrictsType2() throws Exception {
3442  3 testTypes("/** @type {String} */" +
3443    "var a = null;" +
3444    "/** @type (null|undefined) */" +
3445    "var b = a ? null : a;");
3446    }
3447   
 
3448  3 toggle public void testHookRestrictsType3() throws Exception {
3449  3 testTypes("/** @type {String} */" +
3450    "var a;" +
3451    "/** @type (null|undefined) */" +
3452    "var b = (!a) ? a : null;");
3453    }
3454   
 
3455  3 toggle public void testHookRestrictsType4() throws Exception {
3456  3 testTypes("/** @type {(boolean,undefined)} */" +
3457    "var a;" +
3458    "/** @type boolean */" +
3459    "var b = a != null ? a : true;");
3460    }
3461   
 
3462  3 toggle public void testHookRestrictsType5() throws Exception {
3463  3 testTypes("/** @type {(boolean,undefined)} */" +
3464    "var a;" +
3465    "/** @type {(undefined)} */" +
3466    "var b = a == null ? a : undefined;");
3467    }
3468   
 
3469  3 toggle public void testHookRestrictsType6() throws Exception {
3470  3 testTypes("/** @type {(number,null,undefined)} */" +
3471    "var a;" +
3472    "/** @type {number} */" +
3473    "var b = a == null ? 5 : a;");
3474    }
3475   
 
3476  3 toggle public void testHookRestrictsType7() throws Exception {
3477  3 testTypes("/** @type {(number,null,undefined)} */" +
3478    "var a;" +
3479    "/** @type {number} */" +
3480    "var b = a == undefined ? 5 : a;");
3481    }
3482   
 
3483  3 toggle public void testWhileRestrictsType1() throws Exception {
3484  3 testTypes("/** @param {null} x */ function g(x) {}" +
3485    "/** @param {number?} x */\n" +
3486    "function f(x) {\n" +
3487    "while (x) {\n" +
3488    "if (g(x)) { x = 1; }\n" +
3489    "x = x-1;\n}\n}",
3490    "actual parameter 1 of g does not match formal parameter\n" +
3491    "found : number\n" +
3492    "required: null");
3493    }
3494   
 
3495  3 toggle public void testWhileRestrictsType2() throws Exception {
3496  3 testTypes("/** @param {number?} x\n@return {number}*/\n" +
3497    "function f(x) {\n/** @type {number} */var y = 0;" +
3498    "while (x) {\n" +
3499    "y = x;\n" +
3500    "x = x-1;\n}\n" +
3501    "return y;}");
3502    }
3503   
 
3504  3 toggle public void testHigherOrderFunctions1() throws Exception {
3505  3 testTypes(
3506    "/** @type {function(number)} */var f;" +
3507    "f(true);",
3508    "actual parameter 1 of f does not match formal parameter\n" +
3509    "found : boolean\n" +
3510    "required: number");
3511    }
3512   
 
3513  3 toggle public void testHigherOrderFunctions2() throws Exception {
3514  3 testTypes(
3515    "/** @type {function():!Date} */var f;" +
3516    "/** @type boolean */var a = f();",
3517    "initializing variable\n" +
3518    "found : Date\n" +
3519    "required: boolean");
3520    }
3521   
 
3522  3 toggle public void testHigherOrderFunctions3() throws Exception {
3523  3 testTypes(
3524    "/** @type {function(this:Error):Date} */var f; new f",
3525    "cannot instantiate non-constructor");
3526    }
3527   
 
3528  3 toggle public void testHigherOrderFunctions4() throws Exception {
3529  3 testTypes(
3530    "/** @type {function(this:Error,...[number]):Date} */var f; new f",
3531    "cannot instantiate non-constructor");
3532    }
3533   
 
3534  3 toggle public void testConstructorAlias1() throws Exception {
3535  3 testTypes(
3536    "/** @constructor */ var Foo = function() {};" +
3537    "/** @type {number} */ Foo.prototype.bar = 3;" +
3538    "/** @constructor */ var FooAlias = Foo;" +
3539    "/** @return {string} */ function foo() { " +
3540    " return (new FooAlias()).bar; }",
3541    "inconsistent return type\n" +
3542    "found : number\n" +
3543    "required: string");
3544    }
3545   
 
3546  3 toggle public void testConstructorAlias2() throws Exception {
3547  3 testTypes(
3548    "/** @constructor */ var Foo = function() {};" +
3549    "/** @constructor */ var FooAlias = Foo;" +
3550    "/** @type {number} */ FooAlias.prototype.bar = 3;" +
3551    "/** @return {string} */ function foo() { " +
3552    " return (new Foo()).bar; }",
3553    "inconsistent return type\n" +
3554    "found : number\n" +
3555    "required: string");
3556    }
3557   
 
3558  3 toggle public void testConstructorAlias3() throws Exception {
3559  3 testTypes(
3560    "/** @constructor */ var Foo = function() {};" +
3561    "/** @type {number} */ Foo.prototype.bar = 3;" +
3562    "/** @constructor */ var FooAlias = Foo;" +
3563    "/** @return {string} */ function foo() { " +
3564    " return (new FooAlias()).bar; }",
3565    "inconsistent return type\n" +
3566    "found : number\n" +
3567    "required: string");
3568    }
3569   
 
3570  3 toggle public void testConstructorAlias4() throws Exception {
3571  3 testTypes(
3572    "/** @constructor */ var Foo = function() {};" +
3573    "var FooAlias = Foo;" +
3574    "/** @type {number} */ FooAlias.prototype.bar = 3;" +
3575    "/** @return {string} */ function foo() { " +
3576    " return (new Foo()).bar; }",
3577    "inconsistent return type\n" +
3578    "found : number\n" +
3579    "required: string");
3580    }
3581   
 
3582  3 toggle public void testConstructorAlias5() throws Exception {
3583  3 testTypes(
3584    "/** @constructor */ var Foo = function() {};" +
3585    "/** @constructor */ var FooAlias = Foo;" +
3586    "/** @return {FooAlias} */ function foo() { " +
3587    " return new Foo(); }");
3588    }
3589   
 
3590  3 toggle public void testConstructorAlias6() throws Exception {
3591  3 testTypes(
3592    "/** @constructor */ var Foo = function() {};" +
3593    "/** @constructor */ var FooAlias = Foo;" +
3594    "/** @return {Foo} */ function foo() { " +
3595    " return new FooAlias(); }");
3596    }
3597   
 
3598  3 toggle public void testConstructorAlias7() throws Exception {
3599  3 testTypes(
3600    "var goog = {};" +
3601    "/** @constructor */ goog.Foo = function() {};" +
3602    "/** @constructor */ goog.FooAlias = goog.Foo;" +
3603    "/** @return {number} */ function foo() { " +
3604    " return new goog.FooAlias(); }",
3605    "inconsistent return type\n" +
3606    "found : goog.Foo\n" +
3607    "required: number");
3608    }
3609   
 
3610  3 toggle public void testConstructorAlias8() throws Exception {
3611  3 testTypes(
3612    "var goog = {};" +
3613    "/**\n * @param {number} x \n * @constructor */ " +
3614    "goog.Foo = function(x) {};" +
3615    "/**\n * @param {number} x \n * @constructor */ " +
3616    "goog.FooAlias = goog.Foo;" +
3617    "/** @return {number} */ function foo() { " +
3618    " return new goog.FooAlias(1); }",
3619    "inconsistent return type\n" +
3620    "found : goog.Foo\n" +
3621    "required: number");
3622    }
3623   
 
3624  3 toggle public void testConstructorAlias9() throws Exception {
3625  3 testTypes(
3626    "var goog = {};" +
3627    "/**\n * @param {number} x \n * @constructor */ " +
3628    "goog.Foo = function(x) {};" +
3629    "/** @constructor */ goog.FooAlias = goog.Foo;" +
3630    "/** @return {number} */ function foo() { " +
3631    " return new goog.FooAlias(1); }",
3632    "inconsistent return type\n" +
3633    "found : goog.Foo\n" +
3634    "required: number");
3635    }
3636   
 
3637  3 toggle public void testConstructorAlias10() throws Exception {
3638  3 testTypes(
3639    "/**\n * @param {number} x \n * @constructor */ " +
3640    "var Foo = function(x) {};" +
3641    "/** @constructor */ var FooAlias = Foo;" +
3642    "/** @return {number} */ function foo() { " +
3643    " return new FooAlias(1); }",
3644    "inconsistent return type\n" +
3645    "found : Foo\n" +
3646    "required: number");
3647    }
3648   
 
3649  3 toggle public void testClosure1() throws Exception {
3650  3 testClosureTypes(
3651    CLOSURE_DEFS +
3652    "/** @type {string|undefined} */var a;" +
3653    "/** @type string */" +
3654    "var b = goog.isDef(a) ? a : 'default';",
3655    null);
3656    }
3657   
 
3658  3 toggle public void testClosure2() throws Exception {
3659  3 testClosureTypes(
3660    CLOSURE_DEFS +
3661    "/** @type {string|null} */var a;" +
3662    "/** @type string */" +
3663    "var b = goog.isNull(a) ? 'default' : a;",
3664    null);
3665    }
3666   
 
3667  3 toggle public void testClosure3() throws Exception {
3668  3 testClosureTypes(
3669    CLOSURE_DEFS +
3670    "/** @type {string|null|undefined} */var a;" +
3671    "/** @type string */" +
3672    "var b = goog.isDefAndNotNull(a) ? a : 'default';",
3673    null);
3674    }
3675   
 
3676  3 toggle public void testClosure4() throws Exception {
3677  3 testClosureTypes(
3678    CLOSURE_DEFS +
3679    "/** @type {string|undefined} */var a;" +
3680    "/** @type string */" +
3681    "var b = !goog.isDef(a) ? 'default' : a;",
3682    null);
3683    }
3684   
 
3685  3 toggle public void testClosure5() throws Exception {
3686  3 testClosureTypes(
3687    CLOSURE_DEFS +
3688    "/** @type {string|null} */var a;" +
3689    "/** @type string */" +
3690    "var b = !goog.isNull(a) ? a : 'default';",
3691    null);
3692    }
3693   
 
3694  3 toggle public void testClosure6() throws Exception {
3695  3 testClosureTypes(
3696    CLOSURE_DEFS +
3697    "/** @type {string|null|undefined} */var a;" +
3698    "/** @type string */" +
3699    "var b = !goog.isDefAndNotNull(a) ? 'default' : a;",
3700    null);
3701    }
3702   
 
3703  3 toggle public void testReturn1() throws Exception {
3704  3 testTypes("/**@return {void}*/function foo(){ return 3; }",
3705    "inconsistent return type\n" +
3706    "found : number\n" +
3707    "required: undefined");
3708    }
3709   
 
3710  3 toggle public void testReturn2() throws Exception {
3711  3 testTypes("/**@return {!Number}*/function foo(){ return; }",
3712    "inconsistent return type\n" +
3713    "found : undefined\n" +
3714    "required: Number");
3715    }
3716   
 
3717  3 toggle public void testReturn3() throws Exception {
3718  3 testTypes("/**@return {!Number}*/function foo(){ return 'abc'; }",
3719    "inconsistent return type\n" +
3720    "found : string\n" +
3721    "required: Number");
3722    }
3723   
 
3724  3 toggle public void testReturn4() throws Exception {
3725  3 testTypes("/**@return {!Number}\n*/\n function a(){return new Array();}",
3726    "inconsistent return type\n" +
3727    "found : Array\n" +
3728    "required: Number");
3729    }
3730   
 
3731  3 toggle public void testReturn5() throws Exception {
3732  3 testTypes("/** @param {number} n\n" +
3733    "@constructor */function n(n){return};");
3734    }
3735   
 
3736  3 toggle public void testReturn6() throws Exception {
3737  3 testTypes(
3738    "/** @param {number} opt_a\n@return {string} */" +
3739    "function a(opt_a) { return opt_a }",
3740    "inconsistent return type\n" +
3741    "found : (number|undefined)\n" +
3742    "required: string");
3743    }
3744   
 
3745  3 toggle public void testReturn7() throws Exception {
3746  3 testTypes("/** @constructor */var A = function() {};\n" +
3747    "/** @constructor */var B = function() {};\n" +
3748    "/** @return {!B} */A.f = function() { return 1; };",
3749    "inconsistent return type\n" +
3750    "found : number\n" +
3751    "required: B");
3752    }
3753   
 
3754  3 toggle public void testReturn8() throws Exception {
3755  3 testTypes("/** @constructor */var A = function() {};\n" +
3756    "/** @constructor */var B = function() {};\n" +
3757    "/** @return {!B} */A.prototype.f = function() { return 1; };",
3758    "inconsistent return type\n" +
3759    "found : number\n" +
3760    "required: B");
3761    }
3762   
 
3763  3 toggle public void testThis1() throws Exception {
3764  3 testTypes("var goog = {};" +
3765    "/** @constructor */goog.A = function(){};" +
3766    "/** @return {number} */goog.A.prototype.n = " +
3767    " function() { return this };",
3768    "inconsistent return type\n" +
3769    "found : goog.A\n" +
3770    "required: number");
3771    }
3772   
 
3773  3 toggle public void testThis2() throws Exception {
3774  3 testTypes("var goog = {};" +
3775    "/** @constructor */goog.A = function(){" +
3776    " this.foo = null;" +
3777    "};" +
3778    "/** @return {number} */" +
3779    "goog.A.prototype.n = function() { return this.foo };",
3780    "inconsistent return type\n" +
3781    "found : null\n" +
3782    "required: number");
3783    }
3784   
 
3785  3 toggle public void testThis3() throws Exception {
3786  3 testTypes("var goog = {};" +
3787    "/** @constructor */goog.A = function(){" +
3788    " this.foo = null;" +
3789    " this.foo = 5;" +
3790    "};");
3791    }
3792   
 
3793  3 toggle public void testThis4() throws Exception {
3794  3 testTypes("var goog = {};" +
3795    "/** @constructor */goog.A = function(){" +
3796    " /** @type {string?} */this.foo = null;" +
3797    "};" +
3798    "/** @return {number} */goog.A.prototype.n = function() {" +
3799    " return this.foo };",
3800    "inconsistent return type\n" +
3801    "found : (null|string|undefined)\n" +
3802    "required: number");
3803    }
3804   
 
3805  3 toggle public void testThis5() throws Exception {
3806  3 testTypes("/** @this Date\n@return {number}*/function h() { return this }",
3807    "inconsistent return type\n" +
3808    "found : Date\n" +
3809    "required: number");
3810    }
3811   
 
3812  3 toggle public void testThis6() throws Exception {
3813  3 testTypes("var goog = {};" +
3814    "/** @constructor\n@return {!Date} */" +
3815    "goog.A = function(){ return this };",
3816    "inconsistent return type\n" +
3817    "found : goog.A\n" +
3818    "required: Date");
3819    }
3820   
 
3821  3 toggle public void testThis7() throws Exception {
3822  3 testTypes("/** @constructor */function A(){};" +
3823    "/** @return {number} */A.prototype.n = function() { return this };",
3824    "inconsistent return type\n" +
3825    "found : A\n" +
3826    "required: number");
3827    }
3828   
 
3829  3 toggle public void testThis8() throws Exception {
3830  3 testTypes("/** @constructor */function A(){" +
3831    " /** @type {string?} */this.foo = null;" +
3832    "};" +
3833    "/** @return {number} */A.prototype.n = function() {" +
3834    " return this.foo };",
3835    "inconsistent return type\n" +
3836    "found : (null|string|undefined)\n" +
3837    "required: number");
3838    }
3839   
 
3840  3 toggle public void testThis9() throws Exception {
3841    // In A.bar, the type of {@code this} is unknown.
3842  3 testTypes("/** @constructor */function A(){};" +
3843    "A.prototype.foo = 3;" +
3844    "/** @return {string} */ A.bar = function() { return this.foo; };");
3845    }
3846   
 
3847  3 toggle public void testThis10() throws Exception {
3848    // In A.bar, the type of {@code this} is inferred from the @this tag.
3849  3 testTypes("/** @constructor */function A(){};" +
3850    "A.prototype.foo = 3;" +
3851    "/** @this {A}\n@return {string} */" +
3852    "A.bar = function() { return this.foo; };",
3853    "inconsistent return type\n" +
3854    "found : number\n" +
3855    "required: string");
3856    }
3857   
 
3858  3 toggle public void testGlobalThis1() throws Exception {
3859  3 testTypes("/** @constructor */ function Window() {}" +
3860    "/** @param {string} msg */ " +
3861    "Window.prototype.alert = function(msg) {};" +
3862    "this.alert(3);",
3863    "actual parameter 1 of Window.prototype.alert " +
3864    "does not match formal parameter\n" +
3865    "found : number\n" +
3866    "required: string");
3867    }
3868   
 
3869  3 toggle public void testGlobalThis2() throws Exception {
3870  3 testTypes("/** @constructor */ function Bindow() {}" +
3871    "/** @param {string} msg */ " +
3872    "Bindow.prototype.alert = function(msg) {};" +
3873    "this.alert = 3;" +
3874    "(new Bindow()).alert(this.alert)");
3875    }
3876   
 
3877  3 toggle public void testGlobalThis3() throws Exception {
3878  3 testTypes(
3879    "/** @param {string} msg */ " +
3880    "function alert(msg) {};" +
3881    "this.alert(3);",
3882    "actual parameter 1 of global this.alert " +
3883    "does not match formal parameter\n" +
3884    "found : number\n" +
3885    "required: string");
3886    }
3887   
 
3888  3 toggle public void testGlobalThis4() throws Exception {
3889  3 testTypes(
3890    "/** @param {string} msg */ " +
3891    "var alert = function(msg) {};" +
3892    "this.alert(3);",
3893    "actual parameter 1 of global this.alert " +
3894    "does not match formal parameter\n" +
3895    "found : number\n" +
3896    "required: string");
3897    }
3898   
 
3899  3 toggle public void testGlobalThis5() throws Exception {
3900  3 testTypes(
3901    "function f() {" +
3902    " /** @param {string} msg */ " +
3903    " var alert = function(msg) {};" +
3904    "}" +
3905    "this.alert(3);",
3906    "Property alert never defined on global this");
3907    }
3908   
 
3909  3 toggle public void testGlobalThis6() throws Exception {
3910  3 testTypes(
3911    "/** @param {string} msg */ " +
3912    "var alert = function(msg) {};" +
3913    "var x = 3;" +
3914    "x = 'msg';" +
3915    "this.alert(this.x);");
3916    }
3917   
 
3918  3 toggle public void testControlFlowRestrictsType1a() throws Exception {
3919  3 testTypes("/** @return {String?} */ function f() { return null; }\n" +
3920    "/** @type {String?} */ var a = f();\n" +
3921    "/** @type String */ var b = new String('foo');\n" +
3922    "/** @type (null|undefined) */ var c = null;\n" +
3923    "if (a) {\n" +
3924    " b = a;\n" +
3925    "} else {\n" +
3926    " c = a;\n" +
3927    "}");
3928    }
3929   
 
3930  3 toggle public void testControlFlowRestrictsType1b() throws Exception {
3931  3 testTypes("/** @return {!String|null} */ function f() { return null; }\n" +
3932    "/** @type {!String|null} */ var a = f();\n" +
3933    "/** @type String */ var b = new String('foo');\n" +
3934    "/** @type (null) */ var c = null;\n" +
3935    "if (a) {\n" +
3936    " b = a;\n" +
3937    "} else {\n" +
3938    " c = a;\n" +
3939    "}");
3940    }
3941   
 
3942  3 toggle public void testControlFlowRestrictsType1c() throws Exception {
3943  3 testTypes("/** @return {!String|undefined} */\n" +
3944    "function f() { return undefined; }\n" +
3945    "/** @type {!String|undefined} */ var a = f();\n" +
3946    "/** @type String */ var b = new String('foo');\n" +
3947    "/** @type undefined */ var c = undefined;\n" +
3948    "if (a) {\n" +
3949    " b = a;\n" +
3950    "} else {\n" +
3951    " c = a;\n" +
3952    "}");
3953    }
3954   
 
3955  3 toggle public void testControlFlowRestrictsType2() throws Exception {
3956  3 testTypes("/** @return {(string,null)} */ function f() { return null; }" +
3957    "/** @type {(string,null)} */ var a = f();" +
3958    "/** @type string */ var b = 'foo';" +
3959    "/** @type null */ var c = null;" +
3960    "if (a) {" +
3961    " b = a;" +
3962    "} else {" +
3963    " c = a;" +
3964    "}",
3965    "assignment\n" +
3966    "found : (null|string)\n" +
3967    "required: null");
3968    }
3969   
 
3970  3 toggle public void testControlFlowRestrictsType3() throws Exception {
3971  3 testTypes("/** @type {(string,void)} */" +
3972    "var a;" +
3973    "/** @type string */" +
3974    "var b = 'foo';" +
3975    "if (a) {" +
3976    " b = a;" +
3977    "}");
3978    }
3979   
 
3980  3 toggle public void testControlFlowRestrictsType4() throws Exception {
3981  3 testTypes("/** @param {string} a */ function f(a){}" +
3982    "/** @type {(string,undefined)} */ var a;" +
3983    "a && f(a);");
3984    }
3985   
 
3986  3 toggle public void testControlFlowRestrictsType5() throws Exception {
3987  3 testTypes("/** @param {undefined} a */ function f(a){}" +
3988    "/** @type {(!Array,undefined)} */ var a;" +
3989    "a || f(a);");
3990    }
3991   
 
3992  3 toggle public void testControlFlowRestrictsType6() throws Exception {
3993  3 testTypes("/** @param {undefined} x */ function f(x) {}" +
3994    "/** @type {(string,undefined)} */ var a;" +
3995    "a && f(a);",
3996    "actual parameter 1 of f does not match formal parameter\n" +
3997    "found : string\n" +
3998    "required: undefined");
3999    }
4000   
 
4001  3 toggle public void testControlFlowRestrictsType7() throws Exception {
4002  3 testTypes("/** @param {undefined} x */ function f(x) {}" +
4003    "/** @type {(string,undefined)} */ var a;" +
4004    "a && f(a);",
4005    "actual parameter 1 of f does not match formal parameter\n" +
4006    "found : string\n" +
4007    "required: undefined");
4008    }
4009   
 
4010  3 toggle public void testControlFlowRestrictsType8() throws Exception {
4011  3 testTypes("/** @param {undefined} a */ function f(a){}" +
4012    "/** @type {(!Array,undefined)} */ var a;" +
4013    "if (a || f(a)) {}");
4014    }
4015   
 
4016  3 toggle public void testControlFlowRestrictsType9() throws Exception {
4017  3 testTypes("/** @param {number?} x\n * @return {number}*/\n" +
4018    "var f = function(x) {\n" +
4019    "if (!x || x == 1) { return 1; } else { return x; }\n" +
4020    "};");
4021    }
4022   
 
4023  3 toggle public void testSwitchCase3() throws Exception {
4024  3 testTypes("/** @type String */" +
4025    "var a = new String('foo');" +
4026    "switch (a) { case 'A': }");
4027    }
4028   
 
4029  3 toggle public void testSwitchCase4() throws Exception {
4030  3 testTypes("/** @type {(string,Null)} */" +
4031    "var a = 'foo';" +
4032    "switch (a) { case 'A':break; case null:break; }");
4033    }
4034   
 
4035  3 toggle public void testSwitchCase5() throws Exception {
4036  3 testTypes("/** @type {(String,Null)} */" +
4037    "var a = new String('foo');" +
4038    "switch (a) { case 'A':break; case null:break; }");
4039    }
4040   
 
4041  3 toggle public void testSwitchCase6() throws Exception {
4042  3 testTypes("/** @type {(Number,Null)} */" +
4043    "var a = new Number(5);" +
4044    "switch (a) { case 5:break; case null:break; }");
4045    }
4046   
 
4047  3 toggle public void testSwitchCase7() throws Exception {
4048    // This really tests the inference inside the case.
4049  3 testTypes(
4050    "/**\n" +
4051    " * @param {number} x\n" +
4052    " * @return {number}\n" +
4053    " */\n" +
4054    "function g(x) { return 5; }" +
4055    "function f() {" +
4056    " var x = {};" +
4057    " x.foo = '3';" +
4058    " switch (3) { case g(x.foo): return 3; }" +
4059    "}",
4060    "actual parameter 1 of g does not match formal parameter\n" +
4061    "found : string\n" +
4062    "required: number");
4063    }
4064   
 
4065  3 toggle public void testSwitchCase8() throws Exception {
4066    // This really tests the inference inside the switch clause.
4067  3 testTypes(
4068    "/**\n" +
4069    " * @param {number} x\n" +
4070    " * @return {number}\n" +
4071    " */\n" +
4072    "function g(x) { return 5; }" +
4073    "function f() {" +
4074    " var x = {};" +
4075    " x.foo = '3';" +
4076    " switch (g(x.foo)) { case 3: return 3; }" +
4077    "}",
4078    "actual parameter 1 of g does not match formal parameter\n" +
4079    "found : string\n" +
4080    "required: number");
4081    }
4082   
 
4083  3 toggle public void testNoTypeCheck1() throws Exception {
4084  3 testTypes("/** @notypecheck */function foo() { new 4 }");
4085    }
4086   
 
4087  3 toggle public void testNoTypeCheck2() throws Exception {
4088  3 testTypes("/** @notypecheck */var foo = function() { new 4 }");
4089    }
4090   
 
4091  3 toggle public void testNoTypeCheck3() throws Exception {
4092  3 testTypes("/** @notypecheck */var foo = function bar() { new 4 }");
4093    }
4094   
 
4095  3 toggle public void testNoTypeCheck4() throws Exception {
4096  3 testTypes("var foo;" +
4097    "/** @notypecheck */foo = function() { new 4 }");
4098    }
4099   
 
4100  3 toggle public void testNoTypeCheck5() throws Exception {
4101  3 testTypes("var foo;" +
4102    "foo = /** @notypecheck */function() { new 4 }");
4103    }
4104   
 
4105  3 toggle public void testNoTypeCheck6() throws Exception {
4106  3 testTypes("var foo;" +
4107    "/** @notypecheck */foo = function bar() { new 4 }");
4108    }
4109   
 
4110  3 toggle public void testNoTypeCheck7() throws Exception {
4111  3 testTypes("var foo;" +
4112    "foo = /** @notypecheck */function bar() { new 4 }");
4113    }
4114   
 
4115  3 toggle public void testNoTypeCheck8() throws Exception {
4116  3 testTypes("/** @fileoverview \n * @notypecheck */ var foo;" +
4117    "var bar = 3; /** @param {string} x */ function f(x) {} f(bar);");
4118    }
4119   
 
4120  3 toggle public void testImplicitCast() throws Exception {
4121  3 testTypes("/** @constructor */ function Element() {};\n" +
4122    "/** @type {string}\n" +
4123    " * @implicitCast */" +
4124    "Element.prototype.innerHTML;",
4125    "(new Element).innerHTML = new Array();", null, false);
4126    }
4127   
 
4128  3 toggle public void testImplicitCastSubclassAccess() throws Exception {
4129  3 testTypes("/** @constructor */ function Element() {};\n" +
4130    "/** @type {string}\n" +
4131    " * @implicitCast */" +
4132    "Element.prototype.innerHTML;" +
4133    "/** @constructor \n @extends Element */" +
4134    "function DIVElement() {};",
4135    "(new DIVElement).innerHTML = new Array();", null, false);
4136    }
4137   
 
4138  3 toggle public void testImplicitCastNotInExterns() throws Exception {
4139  3 testTypes("/** @constructor */ function Element() {};\n" +
4140    "/** @type {string}\n" +
4141    " * @implicitCast */" +
4142    "Element.prototype.innerHTML;" +
4143    "(new Element).innerHTML = new Array();",
4144    new String[] {
4145    "Illegal annotation on innerHTML. @implicitCast may only be " +
4146    "used in externs.",
4147    "assignment to property innerHTML of Element\n" +
4148    "found : Array\n" +
4149    "required: string"
4150    });
4151    }
4152   
 
4153  3 toggle public void testNumberNode() throws Exception {
4154  3 Node n = typeCheck(Node.newNumber(0));
4155   
4156  3 assertTypeEquals(NUMBER_TYPE, n.getJSType());
4157    }
4158   
 
4159  3 toggle public void testStringNode() throws Exception {
4160  3 Node n = typeCheck(Node.newString("hello"));
4161   
4162  3 assertTypeEquals(STRING_TYPE, n.getJSType());
4163    }
4164   
 
4165  3 toggle public void testBooleanNodeTrue() throws Exception {
4166  3 Node trueNode = typeCheck(new Node(Token.TRUE));
4167   
4168  3 assertTypeEquals(BOOLEAN_TYPE, trueNode.getJSType());
4169    }
4170   
 
4171  3 toggle public void testBooleanNodeFalse() throws Exception {
4172  3 Node falseNode = typeCheck(new Node(Token.FALSE));
4173   
4174  3 assertTypeEquals(BOOLEAN_TYPE, falseNode.getJSType());
4175    }
4176   
 
4177  3 toggle public void testUndefinedNode() throws Exception {
4178  3 Node p = new Node(Token.ADD);
4179  3 Node n = Node.newString(Token.NAME, "undefined");
4180  3 p.addChildToBack(n);
4181  3 p.addChildToBack(Node.newNumber(5));
4182  3 typeCheck(p);
4183   
4184  3 assertTypeEquals(VOID_TYPE, n.getJSType());
4185    }
4186   
 
4187  3 toggle public void testNumberAutoboxing() throws Exception {
4188  3 testTypes("/** @type Number */var a = 4;",
4189    "initializing variable\n" +
4190    "found : number\n" +
4191    "required: (Number|null|undefined)");
4192    }
4193   
 
4194  3 toggle public void testNumberUnboxing() throws Exception {
4195  3 testTypes("/** @type number */var a = new Number(4);",
4196    "initializing variable\n" +
4197    "found : Number\n" +
4198    "required: number");
4199    }
4200   
 
4201  3 toggle public void testStringAutoboxing() throws Exception {
4202  3 testTypes("/** @type String */var a = 'hello';",
4203    "initializing variable\n" +
4204    "found : string\n" +
4205    "required: (String|null|undefined)");
4206    }
4207   
 
4208  3 toggle public void testStringUnboxing() throws Exception {
4209  3 testTypes("/** @type string */var a = new String('hello');",
4210    "initializing variable\n" +
4211    "found : String\n" +
4212    "required: string");
4213    }
4214   
 
4215  3 toggle public void testBooleanAutoboxing() throws Exception {
4216  3 testTypes("/** @type Boolean */var a = true;",
4217    "initializing variable\n" +
4218    "found : boolean\n" +
4219    "required: (Boolean|null|undefined)");
4220    }
4221   
 
4222  3 toggle public void testBooleanUnboxing() throws Exception {
4223  3 testTypes("/** @type boolean */var a = new Boolean(false);",
4224    "initializing variable\n" +
4225    "found : Boolean\n" +
4226    "required: boolean");
4227    }
4228   
 
4229  3 toggle public void testIssue86() throws Exception {
4230  3 testTypes(
4231    "/** @interface */ function I() {}" +
4232    "/** @return {number} */ I.prototype.get = function(){};" +
4233    "/** @constructor \n * @implements {I} */ function F() {}" +
4234    "/** @override */ F.prototype.get = function() { return true; };",
4235    "inconsistent return type\n" +
4236    "found : boolean\n" +
4237    "required: number");
4238    }
4239   
 
4240  3 toggle public void testIssue124() throws Exception {
4241  3 testTypes(
4242    "var t = null;" +
4243    "function test() {" +
4244    " if (t != null) { t = null; }" +
4245    " t = 1;" +
4246    "}");
4247    }
4248   
 
4249  3 toggle public void testIssue124b() throws Exception {
4250  3 testTypes(
4251    "var t = null;" +
4252    "function test() {" +
4253    " if (t != null) { t = null; }" +
4254    " t = undefined;" +
4255    "}",
4256    "condition always evaluates to false\n" +
4257    "left : (null|undefined)\n" +
4258    "right: null");
4259    }
4260   
4261    /**
4262    * Tests that the || operator is type checked correctly, that is of
4263    * the type of the first argument or of the second argument. See
4264    * bugid 592170 for more details.
4265    */
 
4266  3 toggle public void testBug592170() throws Exception {
4267  3 testTypes(
4268    "/** @param {Function} opt_f ... */" +
4269    "function foo(opt_f) {" +
4270    " /** @type {Function} */" +
4271    " return opt_f || function () {};" +
4272    "}",
4273    "Type annotations are not allowed here. Are you missing parentheses?");
4274    }
4275   
4276    /**
4277    * Tests that undefined can be compared shallowly to a value of type
4278    * (number,undefined) regardless of the side on which the undefined
4279    * value is.
4280    */
 
4281  3 toggle public void testBug901455() throws Exception {
4282  3 testTypes("/** @return {(number,undefined)} */ function a() { return 3; }" +
4283    "var b = undefined === a()");
4284  3 testTypes("/** @return {(number,undefined)} */ function a() { return 3; }" +
4285    "var b = a() === undefined");
4286    }
4287   
4288    /**
4289    * Tests that the match method of strings returns nullable arrays.
4290    */
 
4291  3 toggle public void testBug908701() throws Exception {
4292  3 testTypes("/** @type {String} */var s = new String('foo');" +
4293    "var b = s.match(/a/) != null;");
4294    }
4295   
4296    /**
4297    * Tests that named types play nicely with subtyping.
4298    */
 
4299  3 toggle public void testBug908625() throws Exception {
4300  3 testTypes("/** @constructor */function A(){}" +
4301    "/** @constructor\n * @extends A */function B(){}" +
4302    "/** @param {B} b" +
4303    "\n @return {(A,undefined)} */function foo(b){return b}");
4304    }
4305   
4306    /**
4307    * Tests that assigning two untyped functions to a variable whose type is
4308    * inferred and calling this variable is legal.
4309    */
 
4310  3 toggle public void testBug911118() throws Exception {
4311    // verifying the type assigned to anonymous functions assigned variables
4312  3 Scope s = parseAndTypeCheckWithScope("var a = function(){};").scope;
4313  3 JSType type = s.getVar("a").getType();
4314  3 assertEquals("function (): undefined", type.toString());
4315   
4316    // verifying the bug example
4317  3 testTypes("function nullFunction() {};" +
4318    "var foo = nullFunction;" +
4319    "foo = function() {};" +
4320    "foo();");
4321    }
4322   
 
4323  3 toggle public void testBug909000() throws Exception {
4324  3 testTypes("/** @constructor */function A(){}\n" +
4325    "/** @param {!A} a\n" +
4326    "@return {boolean}*/\n" +
4327    "function y(a) { return a }",
4328    "inconsistent return type\n" +
4329    "found : A\n" +
4330    "required: boolean");
4331    }
4332   
 
4333  3 toggle public void testBug930117() throws Exception {
4334  3 testTypes(
4335    "/** @param {boolean} x */function f(x){}" +
4336    "f(null);",
4337    "actual parameter 1 of f does not match formal parameter\n" +
4338    "found : null\n" +
4339    "required: boolean");
4340    }
4341   
 
4342  3 toggle public void testBug1484445() throws Exception {
4343  3 testTypes(
4344    "/** @constructor */ function Foo() {}" +
4345    "/** @type {number?} */ Foo.prototype.bar = null;" +
4346    "/** @type {number?} */ Foo.prototype.baz = null;" +
4347    "/** @param {Foo} foo */" +
4348    "function f(foo) {" +
4349    " while (true) {" +
4350    " if (foo.bar == null && foo.baz == null) {" +
4351    " foo.bar;" +
4352    " }" +
4353    " }" +
4354    "}");
4355    }
4356   
 
4357  3 toggle public void testBug1859535() throws Exception {
4358  3 testTypes(
4359    "/**\n" +
4360    " * @param {Function} childCtor Child class.\n" +
4361    " * @param {Function} parentCtor Parent class.\n" +
4362    " */" +
4363    "var inherits = function(childCtor, parentCtor) {" +
4364    " /** @constructor */" +
4365    " function tempCtor() {};" +
4366    " tempCtor.prototype = parentCtor.prototype;" +
4367    " childCtor.superClass_ = parentCtor.prototype;" +
4368    " childCtor.prototype = new tempCtor();" +
4369    " /** @override */ childCtor.prototype.constructor = childCtor;" +
4370    "};" +
4371    "/**" +
4372    " * @param {Function} constructor\n" +
4373    " * @param {Object} var_args\n" +
4374    " * @return {Object}\n" +
4375    " */" +
4376    "var factory = function(constructor, var_args) {" +
4377    " /** @constructor */" +
4378    " var tempCtor = function() {};" +
4379    " tempCtor.prototype = constructor.prototype;" +
4380    " var obj = new tempCtor();" +
4381    " constructor.apply(obj, arguments);" +
4382    " return obj;" +
4383    "};");
4384    }
4385   
 
4386  3 toggle public void testBug1940591() throws Exception {
4387  3 testTypes(
4388    "/** @type {Object} */" +
4389    "var a = {};\n" +
4390    "/** @type {number} */\n" +
4391    "a.name = 0;\n" +
4392    "/**\n" +
4393    " * @param {Function} x anything.\n" +
4394    " */\n" +
4395    "a.g = function(x) { x.name = 'a'; }");
4396    }
4397   
 
4398  3 toggle public void testBug1942972() throws Exception {
4399  3 testTypes(
4400    "var google = {\n"+
4401    " gears: {\n" +
4402    " factory: {},\n" +
4403    " workerPool: {}\n" +
4404    " }\n" +
4405    "};\n" +
4406    "\n" +
4407    "google.gears = {factory: {}};\n");
4408    }
4409   
 
4410  3 toggle public void testBug1943776() throws Exception {
4411  3 testTypes(
4412    "/** @return {{foo: Array}} */" +
4413    "function bar() {" +
4414    " return {foo: []};" +
4415    "}");
4416    }
4417   
 
4418  3 toggle public void testBug1987544() throws Exception {
4419  3 testTypes(
4420    "/** @param {string} x */ function foo(x) {}" +
4421    "var duration;" +
4422    "if (true && !(duration = 3)) {" +
4423    " foo(duration);" +
4424    "}",
4425    "actual parameter 1 of foo does not match formal parameter\n" +
4426    "found : number\n" +
4427    "required: string");
4428    }
4429   
 
4430  3 toggle public void testBug1940769() throws Exception {
4431  3 testTypes(
4432    "/** @return {!Object} */ " +
4433    "function proto(obj) { return obj.prototype; }" +
4434    "/** @constructor */ function Map() {}" +
4435    "/**\n" +
4436    " * @constructor\n" +
4437    " * @extends {Map}\n" +
4438    " */" +
4439    "function Map2() { Map.call(this); };" +
4440    "Map2.prototype = proto(Map);");
4441    }
4442   
 
4443  3 toggle public void testBug2335992() throws Exception {
4444  3 testTypes(
4445    "/** @return {*} */ function f() { return 3; }" +
4446    "var x = f();" +
4447    "/** @type {string} */" +
4448    "x.y = 3;",
4449    "assignment\n" +
4450    "found : number\n" +
4451    "required: string");
4452    }
4453   
 
4454  3 toggle public void testBug2341812() throws Exception {
4455  3 testTypes(
4456    "/** @interface */" +
4457    "function EventTarget() {}" +
4458    "/** @constructor \n * @implements {EventTarget} */" +
4459    "function Node() {}" +
4460    "/** @type {number} */ Node.prototype.index;" +
4461    "/** @param {EventTarget} x \n * @return {string} */" +
4462    "function foo(x) { return x.index; }");
4463    }
4464   
 
4465  3 toggle public void testScopedConstructors() throws Exception {
4466  3 testTypes(
4467    "function foo1() { " +
4468    " /** @constructor */ function Bar() { " +
4469    " /** @type {number} */ this.x = 3;" +
4470    " }" +
4471    "}" +
4472    "function foo2() { " +
4473    " /** @constructor */ function Bar() { " +
4474    " /** @type {string} */ this.x = 'y';" +
4475    " }" +
4476    " /** " +
4477    " * @param {Bar} b\n" +
4478    " * @return {number}\n" +
4479    " */" +
4480    " function baz(b) { return b.x; }" +
4481    "}",
4482    "inconsistent return type\n" +
4483    "found : string\n" +
4484    "required: number");
4485    }
4486   
 
4487  3 toggle public void testQualifiedNameInference1() throws Exception {
4488  3 testTypes(
4489    "/** @constructor */ function Foo() {}" +
4490    "/** @type {number?} */ Foo.prototype.bar = null;" +
4491    "/** @type {number?} */ Foo.prototype.baz = null;" +
4492    "/** @param {Foo} foo */" +
4493    "function f(foo) {" +
4494    " while (true) {" +
4495    " if (!foo.baz) break; " +
4496    " foo.bar = null;" +
4497    " }" +
4498    // Tests a bug where this condition always evaluated to true.
4499    " return foo.bar == null;" +
4500    "}");
4501    }
4502   
 
4503  3 toggle public void testQualifiedNameInference2() throws Exception {
4504  3 testTypes(
4505    "var x = {};" +
4506    "x.y = c;" +
4507    "function f(a, b) {" +
4508    " if (a) {" +
4509    " if (b) " +
4510    " x.y = 2;" +
4511    " else " +
4512    " x.y = 1;" +
4513    " }" +
4514    " return x.y == null;" +
4515    "}");
4516    }
4517   
 
4518  3 toggle public void testQualifiedNameInference3() throws Exception {
4519  3 testTypes(
4520    "var x = {};" +
4521    "x.y = c;" +
4522    "function f(a, b) {" +
4523    " if (a) {" +
4524    " if (b) " +
4525    " x.y = 2;" +
4526    " else " +
4527    " x.y = 1;" +
4528    " }" +
4529    " return x.y == null;" +
4530    "} function g() { x.y = null; }");
4531    }
4532   
 
4533  3 toggle public void testQualifiedNameInference4() throws Exception {
4534  3 testTypes(
4535    "/** @param {string} x */ function f(x) {}\n" +
4536    "/**\n" +
4537    " * @param {?string} x \n" +
4538    " * @constructor\n" +
4539    " */" +
4540    "function Foo(x) { this.x_ = x; }\n" +
4541    "Foo.prototype.bar = function() {" +
4542    " if (this.x_) { f(this.x_); }" +
4543    "};");
4544    }
4545   
 
4546  3 toggle public void testSheqRefinedScope() throws Exception {
4547  3 Node n = parseAndTypeCheck(
4548    "/** @constructor */function A() {}\n" +
4549    "/** @constructor \n @extends A */ function B() {}\n" +
4550    "/** @return {number} */\n" +
4551    "B.prototype.p = function() { return 1; }\n" +
4552    "/** @param {A} a\n @param {B} b */\n" +
4553    "function f(a, b) {\n" +
4554    " b.p();\n" +
4555    " if (a === b) {\n" +
4556    " b.p();\n" +
4557    " }\n" +
4558    "}");
4559  3 Node nodeC = n.getLastChild().getLastChild().getLastChild().getLastChild()
4560    .getLastChild().getLastChild();
4561  3 JSType typeC = nodeC.getJSType();
4562  3 assertTrue(typeC.isNumber());
4563   
4564  3 Node nodeB = nodeC.getFirstChild().getFirstChild();
4565  3 JSType typeB = nodeB.getJSType();
4566  3 assertEquals("B", typeB.toString());
4567    }
4568   
 
4569  3 toggle public void testAssignToUntypedVariable() throws Exception {
4570  3 Node n = parseAndTypeCheck("var z; z = 1;");
4571   
4572  3 Node assign = n.getLastChild().getFirstChild();
4573  3 Node node = assign.getFirstChild();
4574  3 assertFalse(node.getJSType().isUnknownType());
4575  3 assertEquals("number", node.getJSType().toString());
4576    }
4577   
 
4578  3 toggle public void testAssignToUntypedProperty() throws Exception {
4579  3 Node n = parseAndTypeCheck(
4580    "/** @constructor */ function Foo() {}\n" +
4581    "Foo.prototype.a = 1;" +
4582    "(new Foo).a;");
4583   
4584  3 Node node = n.getLastChild().getFirstChild();
4585  3 assertFalse(node.getJSType().isUnknownType());
4586  3 assertTrue(node.getJSType().isNumber());
4587    }
4588   
 
4589  3 toggle public void testNew1() throws Exception {
4590  3 testTypes("new 4", TypeCheck.NOT_A_CONSTRUCTOR);
4591    }
4592   
 
4593  3 toggle public void testNew2() throws Exception {
4594  3 testTypes("var Math = {}; new Math()", TypeCheck.NOT_A_CONSTRUCTOR);
4595    }
4596   
 
4597  3 toggle public void testNew3() throws Exception {
4598  3 testTypes("new Date()");
4599    }
4600   
 
4601  3 toggle public void testNew4() throws Exception {
4602  3 testTypes("/** @constructor */function A(){}; new A();");
4603    }
4604   
 
4605  3 toggle public void testNew5() throws Exception {
4606  3 testTypes("function A(){}; new A();", TypeCheck.NOT_A_CONSTRUCTOR);
4607    }
4608   
 
4609  3 toggle public void testNew6() throws Exception {
4610  3 TypeCheckResult p =
4611    parseAndTypeCheckWithScope("/** @constructor */function A(){};" +
4612    "var a = new A();");
4613   
4614  3 JSType aType = p.scope.getVar("a").getType();
4615  3 assertTrue(aType instanceof ObjectType);
4616  3 ObjectType aObjectType = (ObjectType) aType;
4617  3 assertEquals("A", aObjectType.getConstructor().getReferenceName());
4618    }
4619   
 
4620  3 toggle public void testNew7() throws Exception {
4621  3 testTypes("/** @param {Function} opt_constructor */" +
4622    "function foo(opt_constructor) {" +
4623    "if (opt_constructor) { new opt_constructor; }" +
4624    "}");
4625    }
4626   
 
4627  3 toggle public void testNew8() throws Exception {
4628  3 testTypes("/** @param {Function} opt_constructor */" +
4629    "function foo(opt_constructor) {" +
4630    "new opt_constructor;" +
4631    "}");
4632    }
4633   
 
4634  3 toggle public void testNew9() throws Exception {
4635  3 testTypes("/** @param {Function} opt_constructor */" +
4636    "function foo(opt_constructor) {" +
4637    "new (opt_constructor || Array);" +
4638    "}");
4639    }
4640   
 
4641  3 toggle public void testNew10() throws Exception {
4642  3 testTypes("var goog = {};" +
4643    "/** @param {Function} opt_constructor */" +
4644    "goog.Foo = function (opt_constructor) {" +
4645    "new (opt_constructor || Array);" +
4646    "}");
4647    }
4648   
 
4649  3 toggle public void testNew11() throws Exception {
4650  3 testTypes("/** @param {Function} c1 */" +
4651    "function f(c1) {" +
4652    " var c2 = function(){};" +
4653    " c1.prototype = new c2;" +
4654    "}", TypeCheck.NOT_A_CONSTRUCTOR);
4655    }
4656   
 
4657  3 toggle public void testNew12() throws Exception {
4658  3 TypeCheckResult p = parseAndTypeCheckWithScope("var a = new Array();");
4659  3 Var a = p.scope.getVar("a");
4660   
4661  3 assertTypeEquals(ARRAY_TYPE, a.getType());
4662    }
4663   
 
4664  3 toggle public void testNew13() throws Exception {
4665  3 TypeCheckResult p = parseAndTypeCheckWithScope(
4666    "/** @constructor */function FooBar(){};" +
4667    "var a = new FooBar();");
4668  3 Var a = p.scope.getVar("a");
4669   
4670  3 assertTrue(a.getType() instanceof ObjectType);
4671  3 assertEquals("FooBar", a.getType().toString());
4672    }
4673   
 
4674  3 toggle public void testNew14() throws Exception {
4675  3 TypeCheckResult p = parseAndTypeCheckWithScope(
4676    "/** @constructor */var FooBar = function(){};" +
4677    "var a = new FooBar();");
4678  3 Var a = p.scope.getVar("a");
4679   
4680  3 assertTrue(a.getType() instanceof ObjectType);
4681  3 assertEquals("FooBar", a.getType().toString());
4682    }
4683   
 
4684  3 toggle public void testNew15() throws Exception {
4685  3 TypeCheckResult p = parseAndTypeCheckWithScope(
4686    "var goog = {};" +
4687    "/** @constructor */goog.A = function(){};" +
4688    "var a = new goog.A();");
4689  3 Var a = p.scope.getVar("a");
4690   
4691  3 assertTrue(a.getType() instanceof ObjectType);
4692  3 assertEquals("goog.A", a.getType().toString());
4693    }
4694   
 
4695  3 toggle public void testNew16() throws Exception {
4696  3 testTypes(
4697    "/** \n" +
4698    " * @param {string} x \n" +
4699    " * @constructor \n" +
4700    " */" +
4701    "function Foo(x) {}" +
4702    "function g() { new Foo(1); }",
4703    "actual parameter 1 of Foo does not match formal parameter\n" +
4704    "found : number\n" +
4705    "required: string");
4706    }
4707   
 
4708  3 toggle public void testName1() throws Exception {
4709  3 assertTypeEquals(VOID_TYPE, testNameNode("undefined"));
4710    }
4711   
 
4712  3 toggle public void testName2() throws Exception {
4713  3 assertTypeEquals(OBJECT_FUNCTION_TYPE, testNameNode("Object"));
4714    }
4715   
 
4716  3 toggle public void testName3() throws Exception {
4717  3 assertTypeEquals(ARRAY_FUNCTION_TYPE, testNameNode("Array"));
4718    }
4719   
 
4720  3 toggle public void testName4() throws Exception {
4721  3 assertTypeEquals(DATE_FUNCTION_TYPE, testNameNode("Date"));
4722    }
4723   
 
4724  3 toggle public void testName5() throws Exception {
4725  3 assertTypeEquals(REGEXP_FUNCTION_TYPE, testNameNode("RegExp"));
4726    }
4727   
4728    /**
4729    * Type checks a NAME node and retrieve its type.
4730    */
 
4731  15 toggle private JSType testNameNode(String name) {
4732  15 Node node = Node.newString(Token.NAME, name);
4733  15 Node parent = new Node(Token.SCRIPT, node);
4734  15 parent.setInputId(new InputId("code"));
4735   
4736  15 Node externs = new Node(Token.SCRIPT);
4737  15 externs.setInputId(new InputId("externs"));
4738   
4739  15 Node externAndJsRoot = new Node(Token.BLOCK, externs, parent);
4740  15 externAndJsRoot.setIsSyntheticBlock(true);
4741   
4742  15 makeTypeCheck().processForTesting(null, parent);
4743  15 return node.getJSType();
4744    }
4745   
 
4746  3 toggle public void testBitOperation1() throws Exception {
4747  3 testTypes("/**@return {void}*/function foo(){ ~foo(); }",
4748    "operator ~ cannot be applied to undefined");
4749    }
4750   
 
4751  3 toggle public void testBitOperation2() throws Exception {
4752  3 testTypes("/**@return {void}*/function foo(){var a = foo()<<3;}",
4753    "operator << cannot be applied to undefined");
4754    }
4755   
 
4756  3 toggle public void testBitOperation3() throws Exception {
4757  3 testTypes("/**@return {void}*/function foo(){var a = 3<<foo();}",
4758    "operator << cannot be applied to undefined");
4759    }
4760   
 
4761  3 toggle public void testBitOperation4() throws Exception {
4762  3 testTypes("/**@return {void}*/function foo(){var a = foo()>>>3;}",
4763    "operator >>> cannot be applied to undefined");
4764    }
4765   
 
4766  3 toggle public void testBitOperation5() throws Exception {
4767  3 testTypes("/**@return {void}*/function foo(){var a = 3>>>foo();}",
4768    "operator >>> cannot be applied to undefined");
4769    }
4770   
 
4771  3 toggle public void testBitOperation6() throws Exception {
4772  3 testTypes("/**@return {!Object}*/function foo(){var a = foo()&3;}",
4773    "bad left operand to bitwise operator\n" +
4774    "found : Object\n" +
4775    "required: (boolean|null|number|string|undefined)");
4776    }
4777   
 
4778  3 toggle public void testBitOperation7() throws Exception {
4779  3 testTypes("var x = null; x |= undefined; x &= 3; x ^= '3'; x |= true;");
4780    }
4781   
 
4782  3 toggle public void testBitOperation8() throws Exception {
4783  3 testTypes("var x = void 0; x |= new Number(3);");
4784    }
4785   
 
4786  3 toggle public void testBitOperation9() throws Exception {
4787  3 testTypes("var x = void 0; x |= {};",
4788    "bad right operand to bitwise operator\n" +
4789    "found : {}\n" +
4790    "required: (boolean|null|number|string|undefined)");
4791    }
4792   
 
4793  3 toggle public void testCall1() throws Exception {
4794  3 testTypes("3();", "number expressions are not callable");
4795    }
4796   
 
4797  3 toggle public void testCall2() throws Exception {
4798  3 testTypes("/** @param {!Number} foo*/function bar(foo){ bar('abc'); }",
4799    "actual parameter 1 of bar does not match formal parameter\n" +
4800    "found : string\n" +
4801    "required: Number");
4802    }
4803   
 
4804  3 toggle public void testCall3() throws Exception {
4805    // We are checking that an unresolved named type can successfully
4806    // meet with a functional type to produce a callable type.
4807  3 testTypes("/** @type {Function|undefined} */var opt_f;" +
4808    "/** @type {some.unknown.type} */var f1;" +
4809    "var f2 = opt_f || f1;" +
4810    "f2();",
4811    "Bad type annotation. Unknown type some.unknown.type");
4812    }
4813   
 
4814  3 toggle public void testCall4() throws Exception {
4815  3 testTypes("/**@param {!RegExp} a*/var foo = function bar(a){ bar('abc'); }",
4816    "actual parameter 1 of bar does not match formal parameter\n" +
4817    "found : string\n" +
4818    "required: RegExp");
4819    }
4820   
 
4821  3 toggle public void testCall5() throws Exception {
4822  3 testTypes("/**@param {!RegExp} a*/var foo = function bar(a){ foo('abc'); }",
4823    "actual parameter 1 of foo does not match formal parameter\n" +
4824    "found : string\n" +
4825    "required: RegExp");
4826    }
4827   
 
4828  3 toggle public void testCall6() throws Exception {
4829  3 testTypes("/** @param {!Number} foo*/function bar(foo){}" +
4830    "bar('abc');",
4831    "actual parameter 1 of bar does not match formal parameter\n" +
4832    "found : string\n" +
4833    "required: Number");
4834    }
4835   
 
4836  3 toggle public void testCall7() throws Exception {
4837  3 testTypes("/** @param {!RegExp} a*/var foo = function bar(a){};" +
4838    "foo('abc');",
4839    "actual parameter 1 of foo does not match formal parameter\n" +
4840    "found : string\n" +
4841    "required: RegExp");
4842    }
4843   
 
4844  3 toggle public void testCall8() throws Exception {
4845  3 testTypes("/** @type {Function|number} */var f;f();",
4846    "(Function|number) expressions are " +
4847    "not callable");
4848    }
4849   
 
4850  3 toggle public void testCall9() throws Exception {
4851  3 testTypes(
4852    "var goog = {};" +
4853    "/** @constructor */ goog.Foo = function() {};" +
4854    "/** @param {!goog.Foo} a */ var bar = function(a){};" +
4855    "bar('abc');",
4856    "actual parameter 1 of bar does not match formal parameter\n" +
4857    "found : string\n" +
4858    "required: goog.Foo");
4859    }
4860   
 
4861  3 toggle public void testCall10() throws Exception {
4862  3 testTypes("/** @type {Function} */var f;f();");
4863    }
4864   
 
4865  3 toggle public void testCall11() throws Exception {
4866  3 testTypes("var f = new Function(); f();");
4867    }
4868   
 
4869  3 toggle public void testFunctionCall1() throws Exception {
4870  3 testTypes(
4871    "/** @param {number} x */ var foo = function(x) {};" +
4872    "foo.call(null, 3);");
4873    }
4874   
 
4875  3 toggle public void testFunctionCall2() throws Exception {
4876  3 testTypes(
4877    "/** @param {number} x */ var foo = function(x) {};" +
4878    "foo.call(null, 'bar');",
4879    "actual parameter 2 of foo.call does not match formal parameter\n" +
4880    "found : string\n" +
4881    "required: number");
4882    }
4883   
 
4884  3 toggle public void testFunctionCall3() throws Exception {
4885  3 testTypes(
4886    "/** @param {number} x \n * @constructor */ " +
4887    "var Foo = function(x) { this.bar.call(null, x); };" +
4888    "/** @type {function(number)} */ Foo.prototype.bar;");
4889    }
4890   
 
4891  3 toggle public void testFunctionCall4() throws Exception {
4892  3 testTypes(
4893    "/** @param {string} x \n * @constructor */ " +
4894    "var Foo = function(x) { this.bar.call(null, x); };" +
4895    "/** @type {function(number)} */ Foo.prototype.bar;",
4896    "actual parameter 2 of this.bar.call " +
4897    "does not match formal parameter\n" +
4898    "found : string\n" +
4899    "required: number");
4900    }
4901   
 
4902  3 toggle public void testFunctionCall5() throws Exception {
4903  3 testTypes(
4904    "/** @param {Function} handler \n * @constructor */ " +
4905    "var Foo = function(handler) { handler.call(this, x); };");
4906    }
4907   
 
4908  3 toggle public void testFunctionCall6() throws Exception {
4909  3 testTypes(
4910    "/** @param {Function} handler \n * @constructor */ " +
4911    "var Foo = function(handler) { handler.apply(this, x); };");
4912    }
4913   
 
4914  3 toggle public void testFunctionCall7() throws Exception {
4915  3 testTypes(
4916    "/** @param {Function} handler \n * @param {Object} opt_context */ " +
4917    "var Foo = function(handler, opt_context) { " +
4918    " handler.call(opt_context, x);" +
4919    "};");
4920    }
4921   
 
4922  3 toggle public void testFunctionCall8() throws Exception {
4923  3 testTypes(
4924    "/** @param {Function} handler \n * @param {Object} opt_context */ " +
4925    "var Foo = function(handler, opt_context) { " +
4926    " handler.apply(opt_context, x);" +
4927    "};");
4928    }
4929   
 
4930  3 toggle public void testCast2() throws Exception {
4931    // can upcast to a base type.
4932  3 testTypes("/** @constructor */function base() {}\n" +
4933    "/** @constructor\n @extends {base} */function derived() {}\n" +
4934    "/** @type {base} */ var baz = new derived();\n");
4935    }
4936   
 
4937  3 toggle public void testCast3() throws Exception {
4938    // cannot downcast
4939  3 testTypes("/** @constructor */function base() {}\n" +
4940    "/** @constructor @extends {base} */function derived() {}\n" +
4941    "/** @type {!derived} */ var baz = new base();\n",
4942    "initializing variable\n" +
4943    "found : base\n" +
4944    "required: derived");
4945    }
4946   
 
4947  3 toggle public void testCast4() throws Exception {
4948    // downcast must be explicit
4949  3 testTypes("/** @constructor */function base() {}\n" +
4950    "/** @constructor\n * @extends {base} */function derived() {}\n" +
4951    "/** @type {!derived} */ var baz = " +
4952    "/** @type {!derived} */(new base());\n");
4953    }
4954   
 
4955  3 toggle public void testCast5() throws Exception {
4956    // cannot explicitly cast to an unrelated type
4957  3 testTypes("/** @constructor */function foo() {}\n" +
4958    "/** @constructor */function bar() {}\n" +
4959    "var baz = /** @type {!foo} */(new bar);\n",
4960    "invalid cast - must be a subtype or supertype\n" +
4961    "from: bar\n" +
4962    "to : foo");
4963    }
4964   
 
4965  3 toggle public void testCast6() throws Exception {
4966    // can explicitly cast to a subtype or supertype
4967  3 testTypes("/** @constructor */function foo() {}\n" +
4968    "/** @constructor \n @extends foo */function bar() {}\n" +
4969    "var baz = /** @type {!bar} */(new bar);\n" +
4970    "var baz = /** @type {!foo} */(new foo);\n" +
4971    "var baz = /** @type {bar} */(new bar);\n" +
4972    "var baz = /** @type {foo} */(new foo);\n" +
4973    "var baz = /** @type {!foo} */(new bar);\n" +
4974    "var baz = /** @type {!bar} */(new foo);\n" +
4975    "var baz = /** @type {foo} */(new bar);\n" +
4976    "var baz = /** @type {bar} */(new foo);\n");
4977    }
4978   
 
4979  3 toggle public void testCast7() throws Exception {
4980  3 testTypes("var x = /** @type {foo} */ (new Object());",
4981    "Bad type annotation. Unknown type foo");
4982    }
4983   
 
4984  3 toggle public void testCast8() throws Exception {
4985  3 testTypes("function f() { return /** @type {foo} */ (new Object()); }",
4986    "Bad type annotation. Unknown type foo");
4987    }
4988   
 
4989  3 toggle public void testCast9() throws Exception {
4990  3 testTypes("var foo = {};" +
4991    "function f() { return /** @type {foo} */ (new Object()); }",
4992    "Bad type annotation. Unknown type foo");
4993    }
4994   
 
4995  3 toggle public void testCast10() throws Exception {
4996  3 testTypes("var foo = function() {};" +
4997    "function f() { return /** @type {foo} */ (new Object()); }",
4998    "Bad type annotation. Unknown type foo");
4999    }
5000   
 
5001  3 toggle public void testCast11() throws Exception {
5002  3 testTypes("var goog = {}; goog.foo = {};" +
5003    "function f() { return /** @type {goog.foo} */ (new Object()); }",
5004    "Bad type annotation. Unknown type goog.foo");
5005    }
5006   
 
5007  3 toggle public void testCast12() throws Exception {
5008  3 testTypes("var goog = {}; goog.foo = function() {};" +
5009    "function f() { return /** @type {goog.foo} */ (new Object()); }",
5010    "Bad type annotation. Unknown type goog.foo");
5011    }
5012   
 
5013  3 toggle public void testCast13() throws Exception {
5014    // Test to make sure that the forward-declaration still allows for
5015    // a warning.
5016  3 testClosureTypes("var goog = {}; " +
5017    "goog.addDependency('zzz.js', ['goog.foo'], []);" +
5018    "goog.foo = function() {};" +
5019    "function f() { return /** @type {goog.foo} */ (new Object()); }",
5020    "Bad type annotation. Unknown type goog.foo");
5021    }
5022   
 
5023  3 toggle public void testCast14() throws Exception {
5024    // Test to make sure that the forward-declaration still prevents
5025    // some warnings.
5026  3 testClosureTypes("var goog = {}; " +
5027    "goog.addDependency('zzz.js', ['goog.bar'], []);" +
5028    "function f() { return /** @type {goog.bar} */ (new Object()); }",
5029    null);
5030    }
5031   
 
5032  3 toggle public void testCast15() throws Exception {
5033    // This fixes a bug where a type cast on an object literal
5034    // would cause a run-time cast exception if the node was visited
5035    // more than once.
5036    //
5037    // Some code assumes that an object literal must have a object type,
5038    // while because of the cast, it could have any type (including
5039    // a union).
5040  3 testTypes(
5041    "for (var i = 0; i < 10; i++) {" +
5042    "var x = /** @type {Object|number} */ ({foo: 3});" +
5043    "/** @param {number} x */ function f(x) {}" +
5044    "f(x.foo);" +
5045    "f([].foo);" +
5046    "}",
5047    "Property foo never defined on Array");
5048    }
5049   
 
5050  3 toggle public void testCast16() throws Exception {
5051    // Mostly verifying that rhino actually understands these JsDocs.
5052  3 testTypes("/** @constructor */ function Foo() {} \n" +
5053    "/** @type {Foo} */ var x = /** @type {Foo} */ ({})");
5054   
5055  3 testTypes("/** @constructor */ function Foo() {} \n" +
5056    "/** @type {Foo} */ var x = (/** @type {Foo} */ y)");
5057    }
5058   
 
5059  3 toggle public void testNestedCasts() throws Exception {
5060  3 testTypes("/** @constructor */var T = function() {};\n" +
5061    "/** @constructor */var V = function() {};\n" +
5062    "/**\n" +
5063    "* @param {boolean} b\n" +
5064    "* @return {T|V}\n" +
5065    "*/\n" +
5066    "function f(b) { return b ? new T() : new V(); }\n" +
5067    "/**\n" +
5068    "* @param {boolean} b\n" +
5069    "* @return {boolean|undefined}\n" +
5070    "*/\n" +
5071    "function g(b) { return b ? true : undefined; }\n" +
5072    "/** @return {T} */\n" +
5073    "function h() {\n" +
5074    "return /** @type {T} */ (f(/** @type {boolean} */ (g(true))));\n" +
5075    "}");
5076    }
5077   
 
5078  3 toggle public void testNativeCast1() throws Exception {
5079  3 testTypes(
5080    "/** @param {number} x */ function f(x) {}" +
5081    "f(String(true));",
5082    "actual parameter 1 of f does not match formal parameter\n" +
5083    "found : string\n" +
5084    "required: number");
5085    }
5086   
 
5087  3 toggle public void testNativeCast2() throws Exception {
5088  3 testTypes(
5089    "/** @param {string} x */ function f(x) {}" +
5090    "f(Number(true));",
5091    "actual parameter 1 of f does not match formal parameter\n" +
5092    "found : number\n" +
5093    "required: string");
5094    }
5095   
 
5096  3 toggle public void testNativeCast3() throws Exception {
5097  3 testTypes(
5098    "/** @param {number} x */ function f(x) {}" +
5099    "f(Boolean(''));",
5100    "actual parameter 1 of f does not match formal parameter\n" +
5101    "found : boolean\n" +
5102    "required: number");
5103    }
5104   
 
5105  3 toggle public void testNativeCast4() throws Exception {
5106  3 testTypes(
5107    "/** @param {number} x */ function f(x) {}" +
5108    "f(Error(''));",
5109    "actual parameter 1 of f does not match formal parameter\n" +
5110    "found : Error\n" +
5111    "required: number");
5112    }
5113   
 
5114  3 toggle public void testBadConstructorCall() throws Exception {
5115  3 testTypes(
5116    "/** @constructor */ function Foo() {}" +
5117    "Foo();",
5118    "Constructor function (new:Foo): undefined should be called " +
5119    "with the \"new\" keyword");
5120    }
5121   
 
5122  3 toggle public void testTypeof() throws Exception {
5123  3 testTypes("/**@return {void}*/function foo(){ var a = typeof foo(); }");
5124    }
5125   
 
5126  3 toggle public void testConstructorType1() throws Exception {
5127  3 testTypes("/**@constructor*/function Foo(){}" +
5128    "/**@type{!Foo}*/var f = new Date();",
5129    "initializing variable\n" +
5130    "found : Date\n" +
5131    "required: Foo");
5132    }
5133   
 
5134  3 toggle public void testConstructorType2() throws Exception {
5135  3 testTypes("/**@constructor*/function Foo(){\n" +
5136    "/**@type{Number}*/this.bar = new Number(5);\n" +
5137    "}\n" +
5138    "/**@type{Foo}*/var f = new Foo();\n" +
5139    "/**@type{Number}*/var n = f.bar;");
5140    }
5141   
 
5142  3 toggle public void testConstructorType3() throws Exception {
5143    // Reverse the declaration order so that we know that Foo is getting set
5144    // even on an out-of-order declaration sequence.
5145  3 testTypes("/**@type{Foo}*/var f = new Foo();\n" +
5146    "/**@type{Number}*/var n = f.bar;" +
5147    "/**@constructor*/function Foo(){\n" +
5148    "/**@type{Number}*/this.bar = new Number(5);\n" +
5149    "}\n");
5150    }
5151   
 
5152  3 toggle public void testConstructorType4() throws Exception {
5153  3 testTypes("/**@constructor*/function Foo(){\n" +
5154    "/**@type{!Number}*/this.bar = new Number(5);\n" +
5155    "}\n" +
5156    "/**@type{!Foo}*/var f = new Foo();\n" +
5157    "/**@type{!String}*/var n = f.bar;",
5158    "initializing variable\n" +
5159    "found : Number\n" +
5160    "required: String");
5161    }
5162   
 
5163  3 toggle public void testConstructorType5() throws Exception {
5164  3 testTypes("/**@constructor*/function Foo(){}\n" +
5165    "if (Foo){}\n");
5166    }
5167   
 
5168  3 toggle public void testConstructorType6() throws Exception {
5169  3 testTypes("/** @constructor */\n" +
5170    "function bar() {}\n" +
5171    "function _foo() {\n" +
5172    " /** @param {bar} x */\n" +
5173    " function f(x) {}\n" +
5174    "}");
5175    }
5176   
 
5177  3 toggle public void testConstructorType7() throws Exception {
5178  3 TypeCheckResult p =
5179    parseAndTypeCheckWithScope("/** @constructor */function A(){};");
5180   
5181  3 JSType type = p.scope.getVar("A").getType();
5182  3 assertTrue(type instanceof FunctionType);
5183  3 FunctionType fType = (FunctionType) type;
5184  3 assertEquals("A", fType.getReferenceName());
5185    }
5186   
 
5187  3 toggle public void testAnonymousType1() throws Exception {
5188  3 testTypes("function f() { return {}; }" +
5189    "/** @constructor */\n" +
5190    "f().bar = function() {};");
5191    }
5192   
 
5193  3 toggle public void testAnonymousType2() throws Exception {
5194  3 testTypes("function f() { return {}; }" +
5195    "/** @interface */\n" +
5196    "f().bar = function() {};");
5197    }
5198   
 
5199  3 toggle public void testAnonymousType3() throws Exception {
5200  3 testTypes("function f() { return {}; }" +
5201    "/** @enum */\n" +
5202    "f().bar = {FOO: 1};");
5203    }
5204   
 
5205  3 toggle public void testBang1() throws Exception {
5206  3 testTypes("/** @param {Object} x\n@return {!Object} */\n" +
5207    "function f(x) { return x; }",
5208    "inconsistent return type\n" +
5209    "found : (Object|null|undefined)\n" +
5210    "required: Object");
5211    }
5212   
 
5213  3 toggle public void testBang2() throws Exception {
5214  3 testTypes("/** @param {Object} x\n@return {!Object} */\n" +
5215    "function f(x) { return x ? x : new Object(); }");
5216    }
5217   
 
5218  3 toggle public void testBang3() throws Exception {
5219  3 testTypes("/** @param {Object} x\n@return {!Object} */\n" +
5220    "function f(x) { return /** @type {!Object} */ (x); }");
5221    }
5222   
 
5223  3 toggle public void testBang4() throws Exception {
5224  3 testTypes("/**@param {Object} x\n@param {Object} y\n@return {boolean}*/\n" +
5225    "function f(x, y) {\n" +
5226    "if (typeof x != 'undefined') { return x == y; }\n" +
5227    "else { return x != y; }\n}");
5228    }
5229   
 
5230  3 toggle public void testBang5() throws Exception {
5231  3 testTypes("/**@param {Object} x\n@param {Object} y\n@return {boolean}*/\n" +
5232    "function f(x, y) { return !!x && x == y; }");
5233    }
5234   
 
5235  3 toggle public void testBang6() throws Exception {
5236  3 testTypes("/** @param {Object?} x\n@return {Object} */\n" +
5237    "function f(x) { return x; }");
5238    }
5239   
 
5240  3 toggle public void testBang7() throws Exception {
5241  3 testTypes("/**@param {(Object,string,null)} x\n" +
5242    "@return {(Object,string)}*/function f(x) { return x; }");
5243    }
5244   
 
5245  3 toggle public void testDefinePropertyOnNullableObject1() throws Exception {
5246  3 testTypes("/** @type {Object} */ var n = {};\n" +
5247    "/** @type {number} */ n.x = 1;\n" +
5248    "/** @return {boolean} */function f() { return n.x; }",
5249    "inconsistent return type\n" +
5250    "found : number\n" +
5251    "required: boolean");
5252    }
5253   
 
5254  3 toggle public void testDefinePropertyOnNullableObject2() throws Exception {
5255  3 testTypes("/** @constructor */ var T = function() {};\n" +
5256    "/** @param {T} t\n@return {boolean} */function f(t) {\n" +
5257    "t.x = 1; return t.x; }",
5258    "inconsistent return type\n" +
5259    "found : number\n" +
5260    "required: boolean");
5261    }
5262   
 
5263  3 toggle public void testUnknownConstructorInstanceType1() throws Exception {
5264  3 testTypes("/** @return {Array} */ function g(f) { return new f(); }");
5265    }
5266   
 
5267  3 toggle public void testUnknownConstructorInstanceType2() throws Exception {
5268  3 testTypes("function g(f) { return /** @type Array */ (new f()); }");
5269    }
5270   
 
5271  3 toggle public void testUnknownConstructorInstanceType3() throws Exception {
5272  3 testTypes("function g(f) { var x = new f(); x.a = 1; return x; }");
5273    }
5274   
 
5275  3 toggle public void testUnknownPrototypeChain() throws Exception {
5276  3 testTypes("/**\n" +
5277    "* @param {Object} co\n" +
5278    " * @return {Object}\n" +
5279    " */\n" +
5280    "function inst(co) {\n" +
5281    " /** @constructor */\n" +
5282    " var c = function() {};\n" +
5283    " c.prototype = co.prototype;\n" +
5284    " return new c;\n" +
5285    "}");
5286    }
5287   
 
5288  3 toggle public void testNamespacedConstructor() throws Exception {
5289  3 Node root = parseAndTypeCheck(
5290    "var goog = {};" +
5291    "/** @constructor */ goog.MyClass = function() {};" +
5292    "/** @return {!goog.MyClass} */ " +
5293    "function foo() { return new goog.MyClass(); }");
5294   
5295  3 JSType typeOfFoo = root.getLastChild().getJSType();
5296  0 assert(typeOfFoo instanceof FunctionType);
5297   
5298  3 JSType retType = ((FunctionType) typeOfFoo).getReturnType();
5299  0 assert(retType instanceof ObjectType);
5300  3 assertEquals("goog.MyClass", ((ObjectType) retType).getReferenceName());
5301    }
5302   
 
5303  3 toggle public void testComplexNamespace() throws Exception {
5304  3 String js =
5305    "var goog = {};" +
5306    "goog.foo = {};" +
5307    "goog.foo.bar = 5;";
5308   
5309  3 TypeCheckResult p = parseAndTypeCheckWithScope(js);
5310   
5311    // goog type in the scope
5312  3 JSType googScopeType = p.scope.getVar("goog").getType();
5313  3 assertTrue(googScopeType instanceof ObjectType);
5314  3 assertTrue("foo property not present on goog type",
5315    ((ObjectType) googScopeType).hasProperty("foo"));
5316  3 assertFalse("bar property present on goog type",
5317    ((ObjectType) googScopeType).hasProperty("bar"));
5318   
5319    // goog type on the VAR node
5320  3 Node varNode = p.root.getFirstChild();
5321  3 assertEquals(Token.VAR, varNode.getType());
5322  3 JSType googNodeType = varNode.getFirstChild().getJSType();
5323  3 assertTrue(googNodeType instanceof ObjectType);
5324   
5325    // goog scope type and goog type on VAR node must be the same
5326  3 assertTrue(googScopeType == googNodeType);
5327   
5328    // goog type on the left of the GETPROP node (under fist ASSIGN)
5329  3 Node getpropFoo1 = varNode.getNext().getFirstChild().getFirstChild();
5330  3 assertEquals(Token.GETPROP, getpropFoo1.getType());
5331  3 assertEquals("goog", getpropFoo1.getFirstChild().getString());
5332  3 JSType googGetpropFoo1Type = getpropFoo1.getFirstChild().getJSType();
5333  3 assertTrue(googGetpropFoo1Type instanceof ObjectType);
5334   
5335    // still the same type as the one on the variable
5336  3 assertTrue(googGetpropFoo1Type == googScopeType);
5337   
5338    // the foo property should be defined on goog
5339  3 JSType googFooType = ((ObjectType) googScopeType).getPropertyType("foo");
5340  3 assertTrue(googFooType instanceof ObjectType);
5341   
5342    // goog type on the left of the GETPROP lower level node
5343    // (under second ASSIGN)
5344  3 Node getpropFoo2 = varNode.getNext().getNext()
5345    .getFirstChild().getFirstChild().getFirstChild();
5346  3 assertEquals(Token.GETPROP, getpropFoo2.getType());
5347  3 assertEquals("goog", getpropFoo2.getFirstChild().getString());
5348  3 JSType googGetpropFoo2Type = getpropFoo2.getFirstChild().getJSType();
5349  3 assertTrue(googGetpropFoo2Type instanceof ObjectType);
5350   
5351    // still the same type as the one on the variable
5352  3 assertTrue(googGetpropFoo2Type == googScopeType);
5353   
5354    // goog.foo type on the left of the top-level GETPROP node
5355    // (under second ASSIGN)
5356  3 JSType googFooGetprop2Type = getpropFoo2.getJSType();
5357  3 assertTrue("goog.foo incorrectly annotated in goog.foo.bar selection",
5358    googFooGetprop2Type instanceof ObjectType);
5359  3 ObjectType googFooGetprop2ObjectType = (ObjectType) googFooGetprop2Type;
5360  3 assertFalse("foo property present on goog.foo type",
5361    googFooGetprop2ObjectType.hasProperty("foo"));
5362  3 assertTrue("bar property not present on goog.foo type",
5363    googFooGetprop2ObjectType.hasProperty("bar"));
5364  3 assertTypeEquals("bar property on goog.foo type incorrectly inferred",
5365    NUMBER_TYPE, googFooGetprop2ObjectType.getPropertyType("bar"));
5366    }
5367   
 
5368  3 toggle public void testAddingMethodsUsingPrototypeIdiomSimpleNamespace()
5369    throws Exception {
5370  3 Node js1Node = parseAndTypeCheck(
5371    "/** @constructor */function A() {}" +
5372    "A.prototype.m1 = 5");
5373   
5374  3 ObjectType instanceType = getInstanceType(js1Node);
5375  3 assertEquals(NATIVE_PROPERTIES_COUNT + 1,
5376    instanceType.getPropertiesCount());
5377  3 checkObjectType(instanceType, "m1", NUMBER_TYPE);
5378    }
5379   
 
5380  3 toggle public void testAddingMethodsUsingPrototypeIdiomComplexNamespace1()
5381    throws Exception {
5382  3 TypeCheckResult p = parseAndTypeCheckWithScope(
5383    "var goog = {};" +
5384    "goog.A = /** @constructor */function() {};" +
5385    "/** @type number */goog.A.prototype.m1 = 5");
5386   
5387  3 testAddingMethodsUsingPrototypeIdiomComplexNamespace(p);
5388    }
5389   
 
5390  3 toggle public void testAddingMethodsUsingPrototypeIdiomComplexNamespace2()
5391    throws Exception {
5392  3 TypeCheckResult p = parseAndTypeCheckWithScope(
5393    "var goog = {};" +
5394    "/** @constructor */goog.A = function() {};" +
5395    "/** @type number */goog.A.prototype.m1 = 5");
5396   
5397  3 testAddingMethodsUsingPrototypeIdiomComplexNamespace(p);
5398    }
5399   
 
5400  6 toggle private void testAddingMethodsUsingPrototypeIdiomComplexNamespace(
5401    TypeCheckResult p) {
5402  6 ObjectType goog = (ObjectType) p.scope.getVar("goog").getType();
5403  6 assertEquals(NATIVE_PROPERTIES_COUNT + 1, goog.getPropertiesCount());
5404  6 JSType googA = goog.getPropertyType("A");
5405  6 assertNotNull(googA);
5406  6 assertTrue(googA instanceof FunctionType);
5407  6 FunctionType googAFunction = (FunctionType) googA;
5408  6 ObjectType classA = googAFunction.getInstanceType();
5409  6 assertEquals(NATIVE_PROPERTIES_COUNT + 1, classA.getPropertiesCount());
5410  6 checkObjectType(classA, "m1", NUMBER_TYPE);
5411    }
5412   
 
5413  3 toggle public void testAddingMethodsPrototypeIdiomAndObjectLiteralSimpleNamespace()
5414    throws Exception {
5415  3 Node js1Node = parseAndTypeCheck(
5416    "/** @constructor */function A() {}" +
5417    "A.prototype = {m1: 5, m2: true}");
5418   
5419  3 ObjectType instanceType = getInstanceType(js1Node);
5420  3 assertEquals(NATIVE_PROPERTIES_COUNT + 2,
5421    instanceType.getPropertiesCount());
5422  3 checkObjectType(instanceType, "m1", NUMBER_TYPE);
5423  3 checkObjectType(instanceType, "m2", BOOLEAN_TYPE);
5424    }
5425   
 
5426  3 toggle public void testDontAddMethodsIfNoConstructor()
5427    throws Exception {
5428  3 Node js1Node = parseAndTypeCheck(
5429    "function A() {}" +
5430    "A.prototype = {m1: 5, m2: true}");
5431   
5432  3 JSType functionAType = js1Node.getFirstChild().getJSType();
5433  3 assertEquals("function (): undefined", functionAType.toString());
5434  3 assertTypeEquals(UNKNOWN_TYPE,
5435    U2U_FUNCTION_TYPE.getPropertyType("m1"));
5436  3 assertTypeEquals(UNKNOWN_TYPE,
5437    U2U_FUNCTION_TYPE.getPropertyType("m2"));
5438    }
5439   
 
5440  3 toggle public void testFunctionAssignement() throws Exception {
5441  3 testTypes("/**" +
5442    "* @param {string} ph0" +
5443    "* @param {string} ph1" +
5444    "* @return {string}" +
5445    "*/" +
5446    "function MSG_CALENDAR_ACCESS_ERROR(ph0, ph1) {return ''}" +
5447    "/** @type {Function} */" +
5448    "var MSG_CALENDAR_ADD_ERROR = MSG_CALENDAR_ACCESS_ERROR;");
5449    }
5450   
 
5451  3 toggle public void testAddMethodsPrototypeTwoWays() throws Exception {
5452  3 Node js1Node = parseAndTypeCheck(
5453    "/** @constructor */function A() {}" +
5454    "A.prototype = {m1: 5, m2: true};" +
5455    "A.prototype.m3 = 'third property!';");
5456   
5457  3 ObjectType instanceType = getInstanceType(js1Node);
5458  3 assertEquals("A", instanceType.toString());
5459  3 assertEquals(NATIVE_PROPERTIES_COUNT + 3,
5460    instanceType.getPropertiesCount());
5461  3 checkObjectType(instanceType, "m1", NUMBER_TYPE);
5462  3 checkObjectType(instanceType, "m2", BOOLEAN_TYPE);
5463  3 checkObjectType(instanceType, "m3", STRING_TYPE);
5464    }
5465   
 
5466  3 toggle public void testPrototypePropertyTypes() throws Exception {
5467  3 Node js1Node = parseAndTypeCheck(
5468    "/** @constructor */function A() {\n" +
5469    " /** @type string */ this.m1;\n" +
5470    " /** @type Object? */ this.m2 = {};\n" +
5471    " /** @type boolean */ this.m3;\n" +
5472    "}\n" +
5473    "/** @type string */ A.prototype.m4;\n" +
5474    "/** @type number */ A.prototype.m5 = 0;\n" +
5475    "/** @type boolean */ A.prototype.m6;\n");
5476   
5477  3 ObjectType instanceType = getInstanceType(js1Node);
5478  3 assertEquals(NATIVE_PROPERTIES_COUNT + 6,
5479    instanceType.getPropertiesCount());
5480  3 checkObjectType(instanceType, "m1", STRING_TYPE);
5481  3 checkObjectType(instanceType, "m2",
5482    createUnionType(createUnionType(OBJECT_TYPE, NULL_TYPE), VOID_TYPE));
5483  3 checkObjectType(instanceType, "m3", BOOLEAN_TYPE);
5484  3 checkObjectType(instanceType, "m4", STRING_TYPE);
5485  3 checkObjectType(instanceType, "m5", NUMBER_TYPE);
5486  3 checkObjectType(instanceType, "m6", BOOLEAN_TYPE);
5487    }
5488   
 
5489  3 toggle public void testValueTypeBuiltInPrototypePropertyType() throws Exception {
5490  3 Node node = parseAndTypeCheck("\"x\".charAt(0)");
5491  3 assertTypeEquals(STRING_TYPE, node.getFirstChild().getFirstChild().getJSType());
5492    }
5493   
 
5494  3 toggle public void testDeclareBuiltInConstructor() throws Exception {
5495    // Built-in prototype properties should be accessible
5496    // even if the built-in constructor is declared.
5497  3 Node node = parseAndTypeCheck(
5498    "/** @constructor */ var String = function(opt_str) {};\n" +
5499    "(new String(\"x\")).charAt(0)");
5500  3 assertTypeEquals(STRING_TYPE, node.getLastChild().getFirstChild().getJSType());
5501    }
5502   
 
5503  3 toggle public void testExtendBuiltInType1() throws Exception {
5504  3 String externs =
5505    "/** @constructor */ var String = function(opt_str) {};\n" +
5506    "/**\n" +
5507    "* @param {number} start\n" +
5508    "* @param {number} opt_length\n" +
5509    "* @return {string}\n" +
5510    "*/\n" +
5511    "String.prototype.substr = function(start, opt_length) {};\n";
5512  3 Node n1 = parseAndTypeCheck(externs + "(new String(\"x\")).substr(0,1);");
5513  3 assertTypeEquals(STRING_TYPE, n1.getLastChild().getFirstChild().getJSType());
5514    }
5515   
 
5516  3 toggle public void testExtendBuiltInType2() throws Exception {
5517  3 String externs =
5518    "/** @constructor */ var String = function(opt_str) {};\n" +
5519    "/**\n" +
5520    "* @param {number} start\n" +
5521    "* @param {number} opt_length\n" +
5522    "* @return {string}\n" +
5523    "*/\n" +
5524    "String.prototype.substr = function(start, opt_length) {};\n";
5525  3 Node n2 = parseAndTypeCheck(externs + "\"x\".substr(0,1);");
5526  3 assertTypeEquals(STRING_TYPE, n2.getLastChild().getFirstChild().getJSType());
5527    }
5528   
 
5529  3 toggle public void testExtendFunction1() throws Exception {
5530  3 Node n = parseAndTypeCheck("/**@return {number}*/Function.prototype.f = " +
5531    "function() { return 1; };\n" +
5532    "(new Function()).f();");
5533  3 JSType type = n.getLastChild().getLastChild().getJSType();
5534  3 assertTypeEquals(NUMBER_TYPE, type);
5535    }
5536   
 
5537  3 toggle public void testExtendFunction2() throws Exception {
5538  3 Node n = parseAndTypeCheck("/**@return {number}*/Function.prototype.f = " +
5539    "function() { return 1; };\n" +
5540    "(function() {}).f();");
5541  3 JSType type = n.getLastChild().getLastChild().getJSType();
5542  3 assertTypeEquals(NUMBER_TYPE, type);
5543    }
5544   
 
5545  3 toggle public void testInheritanceCheck1() throws Exception {
5546  3 testTypes(
5547    "/** @constructor */function Super() {};" +
5548    "/** @constructor\n @extends {Super} */function Sub() {};" +
5549    "Sub.prototype.foo = function() {};");
5550    }
5551   
 
5552  3 toggle public void testInheritanceCheck2() throws Exception {
5553  3 testTypes(
5554    "/** @constructor */function Super() {};" +
5555    "/** @constructor\n @extends {Super} */function Sub() {};" +
5556    "/** @override */Sub.prototype.foo = function() {};",
5557    "property foo not defined on any superclass of Sub");
5558    }
5559   
 
5560  3 toggle public void testInheritanceCheck3() throws Exception {
5561  3 testTypes(
5562    "/** @constructor */function Super() {};" +
5563    "Super.prototype.foo = function() {};" +
5564    "/** @constructor\n @extends {Super} */function Sub() {};" +
5565    "Sub.prototype.foo = function() {};",
5566    "property foo already defined on superclass Super; " +
5567    "use @override to override it");
5568    }
5569   
 
5570  3 toggle public void testInheritanceCheck4() throws Exception {
5571  3 testTypes(
5572    "/** @constructor */function Super() {};" +
5573    "Super.prototype.foo = function() {};" +
5574    "/** @constructor\n @extends {Super} */function Sub() {};" +
5575    "/** @override */Sub.prototype.foo = function() {};");
5576    }
5577   
 
5578  3 toggle public void testInheritanceCheck5() throws Exception {
5579  3 testTypes(
5580    "/** @constructor */function Root() {};" +
5581    "Root.prototype.foo = function() {};" +
5582    "/** @constructor\n @extends {Root} */function Super() {};" +
5583    "/** @constructor\n @extends {Super} */function Sub() {};" +
5584    "Sub.prototype.foo = function() {};",
5585    "property foo already defined on superclass Root; " +
5586    "use @override to override it");
5587    }
5588   
 
5589  3 toggle public void testInheritanceCheck6() throws Exception {
5590  3 testTypes(
5591    "/** @constructor */function Root() {};" +
5592    "Root.prototype.foo = function() {};" +
5593    "/** @constructor\n @extends {Root} */function Super() {};" +
5594    "/** @constructor\n @extends {Super} */function Sub() {};" +
5595    "/** @override */Sub.prototype.foo = function() {};");
5596    }
5597   
 
5598  3 toggle public void testInheritanceCheck7() throws Exception {
5599  3 testTypes(
5600    "var goog = {};" +
5601    "/** @constructor */goog.Super = function() {};" +
5602    "goog.Super.prototype.foo = 3;" +
5603    "/** @constructor\n @extends {goog.Super} */goog.Sub = function() {};" +
5604    "goog.Sub.prototype.foo = 5;");
5605    }
5606   
 
5607  3 toggle public void testInheritanceCheck8() throws Exception {
5608  3 testTypes(
5609    "var goog = {};" +
5610    "/** @constructor */goog.Super = function() {};" +
5611    "goog.Super.prototype.foo = 3;" +
5612    "/** @constructor\n @extends {goog.Super} */goog.Sub = function() {};" +
5613    "/** @override */goog.Sub.prototype.foo = 5;");
5614    }
5615   
 
5616  3 toggle public void testInheritanceCheck9_1() throws Exception {
5617  3 testTypes(
5618    "/** @constructor */function Super() {};" +
5619    "Super.prototype.foo = function() { return 3; };" +
5620    "/** @constructor\n @extends {Super} */function Sub() {};" +
5621    "/** @override\n @return {number} */Sub.prototype.foo =\n" +
5622    "function() { return 1; };");
5623    }
5624   
 
5625  3 toggle public void testInheritanceCheck9_2() throws Exception {
5626  3 testTypes(
5627    "/** @constructor */function Super() {};" +
5628    "/** @return {number} */" +
5629    "Super.prototype.foo = function() { return 1; };" +
5630    "/** @constructor\n @extends {Super} */function Sub() {};" +
5631    "/** @override */Sub.prototype.foo =\n" +
5632    "function() {};");
5633    }
5634   
 
5635  3 toggle public void testInheritanceCheck9_3() throws Exception {
5636  3 testTypes(
5637    "/** @constructor */function Super() {};" +
5638    "/** @return {number} */" +
5639    "Super.prototype.foo = function() { return 1; };" +
5640    "/** @constructor\n @extends {Super} */function Sub() {};" +
5641    "/** @override\n @return {string} */Sub.prototype.foo =\n" +
5642    "function() { return \"some string\" };",
5643    "mismatch of the foo property type and the type of the property it " +
5644    "overrides from superclass Super\n" +
5645    "original: function (this:Super): number\n" +
5646    "override: function (this:Sub): string");
5647    }
5648   
 
5649  3 toggle public void testInheritanceCheck10_1() throws Exception {
5650  3 testTypes(
5651    "/** @constructor */function Root() {};" +
5652    "Root.prototype.foo = function() { return 4; };" +
5653    "/** @constructor\n @extends {Root} */function Super() {};" +
5654    "/** @constructor\n @extends {Super} */function Sub() {};" +
5655    "/** @override\n @return {number} */Sub.prototype.foo =\n" +
5656    "function() { return 1; };");
5657    }
5658   
 
5659  3 toggle public void testInheritanceCheck10_2() throws Exception {
5660  3 testTypes(
5661    "/** @constructor */function Root() {};" +
5662    "/** @return {number} */" +
5663    "Root.prototype.foo = function() { return 1; };" +
5664    "/** @constructor\n @extends {Root} */function Super() {};" +
5665    "/** @constructor\n @extends {Super} */function Sub() {};" +
5666    "/** @override */Sub.prototype.foo =\n" +
5667    "function() {};");
5668    }
5669   
 
5670  3 toggle public void testInheritanceCheck10_3() throws Exception {
5671  3 testTypes(
5672    "/** @constructor */function Root() {};" +
5673    "/** @return {number} */" +
5674    "Root.prototype.foo = function() { return 1; };" +
5675    "/** @constructor\n @extends {Root} */function Super() {};" +
5676    "/** @constructor\n @extends {Super} */function Sub() {};" +
5677    "/** @override\n @return {string} */Sub.prototype.foo =\n" +
5678    "function() { return \"some string\" };",
5679    "mismatch of the foo property type and the type of the property it " +
5680    "overrides from superclass Root\n" +
5681    "original: function (this:Root): number\n" +
5682    "override: function (this:Sub): string");
5683    }
5684   
 
5685  3 toggle public void testInterfaceInheritanceCheck11() throws Exception {
5686  3 testTypes(
5687    "/** @constructor */function Super() {};" +
5688    "/** @param {number} bar */Super.prototype.foo = function(bar) {};" +
5689    "/** @constructor\n @extends {Super} */function Sub() {};" +
5690    "/** @override\n @param {string} bar */Sub.prototype.foo =\n" +
5691    "function(bar) {};",
5692    "mismatch of the foo property type and the type of the property it " +
5693    "overrides from superclass Super\n" +
5694    "original: function (this:Super, number): undefined\n" +
5695    "override: function (this:Sub, string): undefined");
5696    }
5697   
 
5698  3 toggle public void testInheritanceCheck12() throws Exception {
5699  3 testTypes(
5700    "var goog = {};" +
5701    "/** @constructor */goog.Super = function() {};" +
5702    "goog.Super.prototype.foo = 3;" +
5703    "/** @constructor\n @extends {goog.Super} */goog.Sub = function() {};" +
5704    "/** @override */goog.Sub.prototype.foo = \"some string\";");
5705    }
5706   
 
5707  3 toggle public void testInheritanceCheck13() throws Exception {
5708  3 testTypes(
5709    "var goog = {};\n" +
5710    "/** @constructor\n @extends {goog.Missing} */function Sub() {};" +
5711    "/** @override */Sub.prototype.foo = function() {};",
5712    "Bad type annotation. Unknown type goog.Missing");
5713    }
5714   
 
5715  3 toggle public void testInheritanceCheck14() throws Exception {
5716  3 testTypes(
5717    "var goog = {};\n" +
5718    "/** @constructor\n @extends {goog.Missing} */\n" +
5719    "goog.Super = function() {};\n" +
5720    "/** @constructor\n @extends {goog.Super} */function Sub() {};" +
5721    "/** @override */Sub.prototype.foo = function() {};",
5722    "Bad type annotation. Unknown type goog.Missing");
5723    }
5724   
5725    // TODO(user): We should support this way of declaring properties as it is
5726    // widely used.
5727    //public void testInheritanceCheck15() throws Exception {
5728    // testTypes(
5729    // "/** @constructor */function Super() {};" +
5730    // "/** @param {number} bar */Super.prototype.foo;" +
5731    // "/** @constructor\n @extends {Super} */function Sub() {};" +
5732    // "/** @override\n @param {number} bar */Sub.prototype.foo =\n" +
5733    // "function(bar) {};");
5734    //}
5735   
5736    // public void testInterfacePropertyOverride1() throws Exception {
5737    // testTypes(
5738    // "/** @interface */function Super() {};" +
5739    // "/** @desc description */Super.prototype.foo = function() {};" +
5740    // "/** @interface\n @extends {Super} */function Sub() {};" +
5741    // "/** @desc description */Sub.prototype.foo = function() {};",
5742    // "property foo is already defined by the Super extended interface");
5743    // }
5744   
5745    // public void testInterfacePropertyOverride2() throws Exception {
5746    // testTypes(
5747    // "/** @interface */function Root() {};" +
5748    // "/** @desc description */Root.prototype.foo = function() {};" +
5749    // "/** @interface\n @extends {Root} */function Super() {};" +
5750    // "/** @interface\n @extends {Super} */function Sub() {};" +
5751    // "/** @desc description */Sub.prototype.foo = function() {};",
5752    // "property foo is already defined by the Root extended interface");
5753    // }
5754   
 
5755  3 toggle public void testInterfaceInheritanceCheck1() throws Exception {
5756  3 testTypes(
5757    "/** @interface */function Super() {};" +
5758    "/** @desc description */Super.prototype.foo = function() {};" +
5759    "/** @constructor\n @implements {Super} */function Sub() {};" +
5760    "Sub.prototype.foo = function() {};",
5761    "property foo already defined on interface Super; use @override to " +
5762    "override it");
5763    }
5764   
 
5765  3 toggle public void testInterfaceInheritanceCheck2() throws Exception {
5766  3 testTypes(
5767    "/** @interface */function Super() {};" +
5768    "/** @desc description */Super.prototype.foo = function() {};" +
5769    "/** @constructor\n @implements {Super} */function Sub() {};" +
5770    "/** @override */Sub.prototype.foo = function() {};");
5771    }
5772   
 
5773  3 toggle public void testInterfaceInheritanceCheck3() throws Exception {
5774  3 testTypes(
5775    "/** @interface */function Root() {};" +
5776    "/** @return {number} */Root.prototype.foo = function() {};" +
5777    "/** @interface\n @extends {Root} */function Super() {};" +
5778    "/** @constructor\n @implements {Super} */function Sub() {};" +
5779    "/** @return {number} */Sub.prototype.foo = function() { return 1;};",
5780    "property foo already defined on interface Root; use @override to " +
5781    "override it");
5782    }
5783   
 
5784  3 toggle public void testInterfaceInheritanceCheck4() throws Exception {
5785  3 testTypes(
5786    "/** @interface */function Root() {};" +
5787    "/** @return {number} */Root.prototype.foo = function() {};" +
5788    "/** @interface\n @extends {Root} */function Super() {};" +
5789    "/** @constructor\n @implements {Super} */function Sub() {};" +
5790    "/** @override\n * @return {number} */Sub.prototype.foo =\n" +
5791    "function() { return 1;};");
5792    }
5793   
 
5794  3 toggle public void testInterfaceInheritanceCheck5() throws Exception {
5795  3 testTypes(
5796    "/** @interface */function Super() {};" +
5797    "/** @return {string} */Super.prototype.foo = function() {};" +
5798    "/** @constructor\n @implements {Super} */function Sub() {};" +
5799    "/** @override\n @return {number} */Sub.prototype.foo =\n" +
5800    "function() { return 1; };",
5801    "mismatch of the foo property type and the type of the property it " +
5802    "overrides from interface Super\n" +
5803    "original: function (this:Super): string\n" +
5804    "override: function (this:Sub): number");
5805    }
5806   
 
5807  3 toggle public void testInterfaceInheritanceCheck6() throws Exception {
5808  3 testTypes(
5809    "/** @interface */function Root() {};" +
5810    "/** @return {string} */Root.prototype.foo = function() {};" +
5811    "/** @interface\n @extends {Root} */function Super() {};" +
5812    "/** @constructor\n @implements {Super} */function Sub() {};" +
5813    "/** @override\n @return {number} */Sub.prototype.foo =\n" +
5814    "function() { return 1; };",
5815    "mismatch of the foo property type and the type of the property it " +
5816    "overrides from interface Root\n" +
5817    "original: function (this:Root): string\n" +
5818    "override: function (this:Sub): number");
5819    }
5820   
 
5821  3 toggle public void testInterfaceInheritanceCheck7() throws Exception {
5822  3 testTypes(
5823    "/** @interface */function Super() {};" +
5824    "/** @param {number} bar */Super.prototype.foo = function(bar) {};" +
5825    "/** @constructor\n @implements {Super} */function Sub() {};" +
5826    "/** @override\n @param {string} bar */Sub.prototype.foo =\n" +
5827    "function(bar) {};",
5828    "mismatch of the foo property type and the type of the property it " +
5829    "overrides from interface Super\n" +
5830    "original: function (this:Super, number): undefined\n" +
5831    "override: function (this:Sub, string): undefined");
5832    }
5833   
 
5834  3 toggle public void testInterfaceInheritanceCheck8() throws Exception {
5835  3 testTypes(
5836    "/** @constructor\n @implements {Super} */function Sub() {};" +
5837    "/** @override */Sub.prototype.foo = function() {};",
5838    new String[] {
5839    "Bad type annotation. Unknown type Super",
5840    "property foo not defined on any superclass of Sub"
5841    });
5842    }
5843   
 
5844  3 toggle public void testInterfacePropertyNotImplemented() throws Exception {
5845  3 testTypes(
5846    "/** @interface */function Int() {};" +
5847    "/** @desc description */Int.prototype.foo = function() {};" +
5848    "/** @constructor\n @implements {Int} */function Foo() {};",
5849    "property foo on interface Int is not implemented by type Foo");
5850    }
5851   
 
5852  3 toggle public void testInterfacePropertyNotImplemented2() throws Exception {
5853  3 testTypes(
5854    "/** @interface */function Int() {};" +
5855    "/** @desc description */Int.prototype.foo = function() {};" +
5856    "/** @interface \n @extends {Int} */function Int2() {};" +
5857    "/** @constructor\n @implements {Int2} */function Foo() {};",
5858    "property foo on interface Int is not implemented by type Foo");
5859    }
5860   
 
5861  3 toggle public void testStubConstructorImplementingInterface() throws Exception {
5862    // This does not throw a warning for unimplemented property because Foo is
5863    // just a stub.
5864  3 testTypes(
5865    // externs
5866    "/** @interface */ function Int() {}\n" +
5867    "/** @desc description */Int.prototype.foo = function() {};" +
5868    "/** @constructor \n @implements {Int} */ var Foo;\n",
5869    "", null, false);
5870    }
5871   
 
5872  3 toggle public void testObjectLiteral() throws Exception {
5873  3 Node n = parseAndTypeCheck("var a = {m1: 7, m2: 'hello'}");
5874   
5875  3 Node nameNode = n.getFirstChild().getFirstChild();
5876  3 Node objectNode = nameNode.getFirstChild();
5877   
5878    // node extraction
5879  3 assertEquals(Token.NAME, nameNode.getType());
5880  3 assertEquals(Token.OBJECTLIT, objectNode.getType());
5881   
5882    // value's type
5883  3 ObjectType objectType =
5884    (ObjectType) objectNode.getJSType();
5885  3 assertTypeEquals(NUMBER_TYPE, objectType.getPropertyType("m1"));
5886  3 assertTypeEquals(STRING_TYPE, objectType.getPropertyType("m2"));
5887   
5888    // variable's type
5889  3 assertTypeEquals(objectType, nameNode.getJSType());
5890    }
5891   
 
5892  3 toggle public void testObjectLiteralDeclaration1() throws Exception {
5893  3 testTypes(
5894    "var x = {" +
5895    "/** @type {boolean} */ abc: true," +
5896    "/** @type {number} */ 'def': 0," +
5897    "/** @type {string} */ 3: 'fgh'" +
5898    "};");
5899    }
5900   
 
5901  3 toggle public void testCallDateConstructorAsFunction() throws Exception {
5902    // ECMA-262 15.9.2: When Date is called as a function rather than as a
5903    // constructor, it returns a string.
5904  3 Node n = parseAndTypeCheck("Date()");
5905  3 assertTypeEquals(STRING_TYPE, n.getFirstChild().getFirstChild().getJSType());
5906    }
5907   
5908    // According to ECMA-262, Error & Array function calls are equivalent to
5909    // constructor calls.
5910   
 
5911  3 toggle public void testCallErrorConstructorAsFunction() throws Exception {
5912  3 Node n = parseAndTypeCheck("Error('x')");
5913  3 assertTypeEquals(ERROR_TYPE,
5914    n.getFirstChild().getFirstChild().getJSType());
5915    }
5916   
 
5917  3 toggle public void testCallArrayConstructorAsFunction() throws Exception {
5918  3 Node n = parseAndTypeCheck("Array()");
5919  3 assertTypeEquals(ARRAY_TYPE,
5920    n.getFirstChild().getFirstChild().getJSType());
5921    }
5922   
 
5923  3 toggle public void testPropertyTypeOfUnionType() throws Exception {
5924  3 testTypes("var a = {};" +
5925    "/** @constructor */ a.N = function() {};\n" +
5926    "a.N.prototype.p = 1;\n" +
5927    "/** @constructor */ a.S = function() {};\n" +
5928    "a.S.prototype.p = 'a';\n" +
5929    "/** @param {!a.N|!a.S} x\n@return {string} */\n" +
5930    "var f = function(x) { return x.p; };",
5931    "inconsistent return type\n" +
5932    "found : (number|string)\n" +
5933    "required: string");
5934    }
5935   
5936    // TODO(user): We should flag these as invalid. This will probably happen
5937    // when we make sure the interface is never referenced outside of its
5938    // definition. We might want more specific and helpful error messages.
5939    //public void testWarningOnInterfacePrototype() throws Exception {
5940    // testTypes("/** @interface */ u.T = function() {};\n" +
5941    // "/** @return {number} */ u.T.prototype = function() { };",
5942    // "cannot reference an interface outside of its definition");
5943    //}
5944    //
5945    //public void testBadPropertyOnInterface1() throws Exception {
5946    // testTypes("/** @interface */ u.T = function() {};\n" +
5947    // "/** @return {number} */ u.T.f = function() { return 1;};",
5948    // "cannot reference an interface outside of its definition");
5949    //}
5950    //
5951    //public void testBadPropertyOnInterface2() throws Exception {
5952    // testTypes("/** @interface */ function T() {};\n" +
5953    // "/** @return {number} */ T.f = function() { return 1;};",
5954    // "cannot reference an interface outside of its definition");
5955    //}
5956    //
5957    //public void testBadPropertyOnInterface3() throws Exception {
5958    // testTypes("/** @interface */ u.T = function() {}; u.T.x",
5959    // "cannot reference an interface outside of its definition");
5960    //}
5961    //
5962    //public void testBadPropertyOnInterface4() throws Exception {
5963    // testTypes("/** @interface */ function T() {}; T.x;",
5964    // "cannot reference an interface outside of its definition");
5965    //}
5966   
 
5967  3 toggle public void testAnnotatedPropertyOnInterface1() throws Exception {
5968    // For interfaces we must allow function definitions that don't have a
5969    // return statement, even though they declare a returned type.
5970  3 testTypes("/** @interface */ u.T = function() {};\n" +
5971    "/** @return {number} */ u.T.prototype.f = function() {};");
5972    }
5973   
 
5974  3 toggle public void testAnnotatedPropertyOnInterface2() throws Exception {
5975  3 testTypes("/** @interface */ u.T = function() {};\n" +
5976    "/** @return {number} */ u.T.prototype.f = function() { };");
5977    }
5978   
 
5979  3 toggle public void testAnnotatedPropertyOnInterface3() throws Exception {
5980  3 testTypes("/** @interface */ function T() {};\n" +
5981    "/** @return {number} */ T.prototype.f = function() { };");
5982    }
5983   
 
5984  3 toggle public void testAnnotatedPropertyOnInterface4() throws Exception {
5985  3 testTypes(
5986    CLOSURE_DEFS +
5987    "/** @interface */ function T() {};\n" +
5988    "/** @return {number} */ T.prototype.f = goog.abstractMethod;");
5989    }
5990   
5991    // TODO(user): If we want to support this syntax we have to warn about
5992    // missing annotations.
5993    //public void testWarnUnannotatedPropertyOnInterface1() throws Exception {
5994    // testTypes("/** @interface */ u.T = function () {}; u.T.prototype.x;",
5995    // "interface property x is not annotated");
5996    //}
5997    //
5998    //public void testWarnUnannotatedPropertyOnInterface2() throws Exception {
5999    // testTypes("/** @interface */ function T() {}; T.prototype.x;",
6000    // "interface property x is not annotated");
6001    //}
6002   
 
6003  3 toggle public void testWarnUnannotatedPropertyOnInterface5() throws Exception {
6004  3 testTypes("/** @interface */ u.T = function () {};\n" +
6005    "/** @desc x does something */u.T.prototype.x = function() {};");
6006    }
6007   
 
6008  3 toggle public void testWarnUnannotatedPropertyOnInterface6() throws Exception {
6009  3 testTypes("/** @interface */ function T() {};\n" +
6010    "/** @desc x does something */T.prototype.x = function() {};");
6011    }
6012   
6013    // TODO(user): If we want to support this syntax we have to warn about
6014    // the invalid type of the interface member.
6015    //public void testWarnDataPropertyOnInterface1() throws Exception {
6016    // testTypes("/** @interface */ u.T = function () {};\n" +
6017    // "/** @type {number} */u.T.prototype.x;",
6018    // "interface members can only be plain functions");
6019    //}
6020    //
6021    //public void testWarnDataPropertyOnInterface2() throws Exception {
6022    // testTypes("/** @interface */ function T() {};\n" +
6023    // "/** @type {number} */T.prototype.x;",
6024    // "interface members can only be plain functions");
6025    //}
6026   
 
6027  3 toggle public void testWarnDataPropertyOnInterface3() throws Exception {
6028  3 testTypes("/** @interface */ u.T = function () {};\n" +
6029    "/** @type {number} */u.T.prototype.x = 1;",
6030    "interface members can only be empty property declarations, "
6031    + "empty functions, or goog.abstractMethod");
6032    }
6033   
 
6034  3 toggle public void testWarnDataPropertyOnInterface4() throws Exception {
6035  3 testTypes("/** @interface */ function T() {};\n" +
6036    "/** @type {number} */T.prototype.x = 1;",
6037    "interface members can only be empty property declarations, "
6038    + "empty functions, or goog.abstractMethod");
6039    }
6040   
6041    // TODO(user): If we want to support this syntax we should warn about the
6042    // mismatching types in the two tests below.
6043    //public void testErrorMismatchingPropertyOnInterface1() throws Exception {
6044    // testTypes("/** @interface */ u.T = function () {};\n" +
6045    // "/** @param {Number} foo */u.T.prototype.x =\n" +
6046    // "/** @param {String} foo */function(foo) {};",
6047    // "found : \n" +
6048    // "required: ");
6049    //}
6050    //
6051    //public void testErrorMismatchingPropertyOnInterface2() throws Exception {
6052    // testTypes("/** @interface */ function T() {};\n" +
6053    // "/** @return {number} */T.prototype.x =\n" +
6054    // "/** @return {string} */function() {};",
6055    // "found : \n" +
6056    // "required: ");
6057    //}
6058   
6059    // TODO(user): We should warn about this (bar is missing an annotation). We
6060    // probably don't want to warn about all missing parameter annotations, but
6061    // we should be as strict as possible regarding interfaces.
6062    //public void testErrorMismatchingPropertyOnInterface3() throws Exception {
6063    // testTypes("/** @interface */ u.T = function () {};\n" +
6064    // "/** @param {Number} foo */u.T.prototype.x =\n" +
6065    // "function(foo, bar) {};",
6066    // "found : \n" +
6067    // "required: ");
6068    //}
6069   
 
6070  3 toggle public void testErrorMismatchingPropertyOnInterface4() throws Exception {
6071  3 testTypes("/** @interface */ u.T = function () {};\n" +
6072    "/** @param {Number} foo */u.T.prototype.x =\n" +
6073    "function() {};",
6074    "parameter foo does not appear in u.T.prototype.x's parameter list");
6075    }
6076   
 
6077  3 toggle public void testErrorMismatchingPropertyOnInterface5() throws Exception {
6078  3 testTypes("/** @interface */ function T() {};\n" +
6079    "/** @type {number} */T.prototype.x = function() { };",
6080    "assignment to property x of T.prototype\n" +
6081    "found : function (): undefined\n" +
6082    "required: number");
6083    }
6084   
 
6085  3 toggle public void testErrorMismatchingPropertyOnInterface6() throws Exception {
6086  3 testClosureTypesMultipleWarnings(
6087    "/** @interface */ function T() {};\n" +
6088    "/** @return {number} */T.prototype.x = 1",
6089    Lists.newArrayList(
6090    "assignment to property x of T.prototype\n" +
6091    "found : number\n" +
6092    "required: function (this:T): number",
6093    "interface members can only be empty property declarations, " +
6094    "empty functions, or goog.abstractMethod"));
6095    }
6096   
 
6097  3 toggle public void testInterfaceNonEmptyFunction() throws Exception {
6098  3 testTypes("/** @interface */ function T() {};\n" +
6099    "T.prototype.x = function() { return 'foo'; }",
6100    "interface member functions must have an empty body"
6101    );
6102    }
6103   
 
6104  3 toggle public void testDoubleNestedInterface() throws Exception {
6105  3 testTypes("/** @interface */ var I1 = function() {};\n" +
6106    "/** @interface */ I1.I2 = function() {};\n" +
6107    "/** @interface */ I1.I2.I3 = function() {};\n");
6108    }
6109   
 
6110  3 toggle public void testStaticDataPropertyOnNestedInterface() throws Exception {
6111  3 testTypes("/** @interface */ var I1 = function() {};\n" +
6112    "/** @interface */ I1.I2 = function() {};\n" +
6113    "/** @type {number} */ I1.I2.x = 1;\n");
6114    }
6115   
 
6116  3 toggle public void testInterfaceInstantiation() throws Exception {
6117  3 testTypes("/** @interface */var f = function(){}; new f",
6118    "cannot instantiate non-constructor");
6119    }
6120   
 
6121  3 toggle public void testPrototypeLoop() throws Exception {
6122  3 testClosureTypesMultipleWarnings(
6123    suppressMissingProperty("foo") +
6124    "/** @constructor \n * @extends {T} */var T = function() {};" +
6125    "alert((new T).foo);",
6126    Lists.newArrayList(
6127    "Parse error. Cycle detected in inheritance chain of type T",
6128    "Could not resolve type in @extends tag of T"));
6129    }
6130   
 
6131  3 toggle public void testDirectPrototypeAssign() throws Exception {
6132    // For now, we just ignore @type annotations on the prototype.
6133  3 testTypes(
6134    "/** @constructor */ function Foo() {}" +
6135    "/** @constructor */ function Bar() {}" +
6136    "/** @type {Array} */ Bar.prototype = new Foo()");
6137    }
6138   
6139    // In all testResolutionViaRegistry* tests, since u is unknown, u.T can only
6140    // be resolved via the registry and not via properties.
6141   
 
6142  3 toggle public void testResolutionViaRegistry1() throws Exception {
6143  3 testTypes("/** @constructor */ u.T = function() {};\n" +
6144    "/** @type {(number|string)} */ u.T.prototype.a;\n" +
6145    "/**\n" +
6146    "* @param {u.T} t\n" +
6147    "* @return {string}\n" +
6148    "*/\n" +
6149    "var f = function(t) { return t.a; };",
6150    "inconsistent return type\n" +
6151    "found : (number|string)\n" +
6152    "required: string");
6153    }
6154   
 
6155  3 toggle public void testResolutionViaRegistry2() throws Exception {
6156  3 testTypes(
6157    "/** @constructor */ u.T = function() {" +
6158    " this.a = 0; };\n" +
6159    "/**\n" +
6160    "* @param {u.T} t\n" +
6161    "* @return {string}\n" +
6162    "*/\n" +
6163    "var f = function(t) { return t.a; };",
6164    "inconsistent return type\n" +
6165    "found : number\n" +
6166    "required: string");
6167    }
6168   
 
6169  3 toggle public void testResolutionViaRegistry3() throws Exception {
6170  3 testTypes("/** @constructor */ u.T = function() {};\n" +
6171    "/** @type {(number|string)} */ u.T.prototype.a = 0;\n" +
6172    "/**\n" +
6173    "* @param {u.T} t\n" +
6174    "* @return {string}\n" +
6175    "*/\n" +
6176    "var f = function(t) { return t.a; };",
6177    "inconsistent return type\n" +
6178    "found : (number|string)\n" +
6179    "required: string");
6180    }
6181   
 
6182  3 toggle public void testResolutionViaRegistry4() throws Exception {
6183  3 testTypes("/** @constructor */ u.A = function() {};\n" +
6184    "/**\n* @constructor\n* @extends {u.A}\n*/\nu.A.A = function() {}\n;" +
6185    "/**\n* @constructor\n* @extends {u.A}\n*/\nu.A.B = function() {};\n" +
6186    "var ab = new u.A.B();\n" +
6187    "/** @type {!u.A} */ var a = ab;\n" +
6188    "/** @type {!u.A.A} */ var aa = ab;\n",
6189    "initializing variable\n" +
6190    "found : u.A.B\n" +
6191    "required: u.A.A");
6192    }
6193   
 
6194  3 toggle public void testResolutionViaRegistry5() throws Exception {
6195  3 Node n = parseAndTypeCheck("/** @constructor */ u.T = function() {}; u.T");
6196  3 JSType type = n.getLastChild().getLastChild().getJSType();
6197  3 assertFalse(type.isUnknownType());
6198  3 assertTrue(type instanceof FunctionType);
6199  3 assertEquals("u.T",
6200    ((FunctionType) type).getInstanceType().getReferenceName());
6201    }
6202   
 
6203  3 toggle public void testGatherProperyWithoutAnnotation1() throws Exception {
6204  3 Node n = parseAndTypeCheck("/** @constructor */ var T = function() {};" +
6205    "/** @type {!T} */var t; t.x; t;");
6206  3 JSType type = n.getLastChild().getLastChild().getJSType();
6207  3 assertFalse(type.isUnknownType());
6208  3 assertTrue(type instanceof ObjectType);
6209  3 ObjectType objectType = (ObjectType) type;
6210  3 assertFalse(objectType.hasProperty("x"));
6211  3 Asserts.assertTypeCollectionEquals(
6212    Lists.newArrayList(objectType),
6213    registry.getTypesWithProperty("x"));
6214    }
6215   
 
6216  3 toggle public void testGatherProperyWithoutAnnotation2() throws Exception {
6217  3 TypeCheckResult ns =
6218    parseAndTypeCheckWithScope("/** @type {!Object} */var t; t.x; t;");
6219  3 Node n = ns.root;
6220  3 Scope s = ns.scope;
6221  3 JSType type = n.getLastChild().getLastChild().getJSType();
6222  3 assertFalse(type.isUnknownType());
6223  3 assertTypeEquals(type, OBJECT_TYPE);
6224  3 assertTrue(type instanceof ObjectType);
6225  3 ObjectType objectType = (ObjectType) type;
6226  3 assertFalse(objectType.hasProperty("x"));
6227  3 Asserts.assertTypeCollectionEquals(
6228    Lists.newArrayList(OBJECT_TYPE),
6229    registry.getTypesWithProperty("x"));
6230    }
6231   
 
6232  3 toggle public void testFunctionMasksVariableBug() throws Exception {
6233  3 testTypes("var x = 4; var f = function x(b) { return b ? 1 : x(true); };",
6234    "function x masks variable (IE bug)");
6235    }
6236   
 
6237  3 toggle public void testDfa1() throws Exception {
6238  3 testTypes("var x = null;\n x = 1;\n /** @type number */ var y = x;");
6239    }
6240   
 
6241  3 toggle public void testDfa2() throws Exception {
6242  3 testTypes("function u() {}\n" +
6243    "/** @return {number} */ function f() {\nvar x = 'todo';\n" +
6244    "if (u()) { x = 1; } else { x = 2; } return x;\n}");
6245    }
6246   
 
6247  3 toggle public void testDfa3() throws Exception {
6248  3 testTypes("function u() {}\n" +
6249    "/** @return {number} */ function f() {\n" +
6250    "/** @type {number|string} */ var x = 'todo';\n" +
6251    "if (u()) { x = 1; } else { x = 2; } return x;\n}");
6252    }
6253   
 
6254  3 toggle public void testDfa4() throws Exception {
6255  3 testTypes("/** @param {Date?} d */ function f(d) {\n" +
6256    "if (!d) { return; }\n" +
6257    "/** @type {!Date} */ var e = d;\n}");
6258    }
6259   
 
6260  3 toggle public void testDfa5() throws Exception {
6261  3 testTypes("/** @return {string?} */ function u() {return 'a';}\n" +
6262    "/** @param {string?} x\n@return {string} */ function f(x) {\n" +
6263    "while (!x) { x = u(); }\nreturn x;\n}");
6264    }
6265   
 
6266  3 toggle public void testDfa6() throws Exception {
6267  3 testTypes("/** @return {Object?} */ function u() {return {};}\n" +
6268    "/** @param {Object?} x */ function f(x) {\n" +
6269    "while (x) { x = u(); if (!x) { x = u(); } }\n}");
6270    }
6271   
 
6272  3 toggle public void testDfa7() throws Exception {
6273  3 testTypes("/** @constructor */ var T = function() {};\n" +
6274    "/** @type {Date?} */ T.prototype.x = null;\n" +
6275    "/** @param {!T} t */ function f(t) {\n" +
6276    "if (!t.x) { return; }\n" +
6277    "/** @type {!Date} */ var e = t.x;\n}");
6278    }
6279   
 
6280  3 toggle public void testDfa8() throws Exception {
6281  3 testTypes("/** @constructor */ var T = function() {};\n" +
6282    "/** @type {number|string} */ T.prototype.x = '';\n" +
6283    "function u() {}\n" +
6284    "/** @param {!T} t\n@return {number} */ function f(t) {\n" +
6285    "if (u()) { t.x = 1; } else { t.x = 2; } return t.x;\n}");
6286    }
6287   
 
6288  3 toggle public void testDfa9() throws Exception {
6289  3 testTypes("function f() {\n/** @type {string?} */var x;\nx = null;\n" +
6290    "if (x == null) { return 0; } else { return 1; } }",
6291    "condition always evaluates to true\n" +
6292    "left : null\n" +
6293    "right: null");
6294    }
6295   
 
6296  3 toggle public void testDfa10() throws Exception {
6297  3 testTypes("/** @param {null} x */ function g(x) {}" +
6298    "/** @param {string?} x */function f(x) {\n" +
6299    "if (!x) { x = ''; }\n" +
6300    "if (g(x)) { return 0; } else { return 1; } }",
6301    "actual parameter 1 of g does not match formal parameter\n" +
6302    "found : string\n" +
6303    "required: null");
6304    }
6305   
 
6306  3 toggle public void testDfa11() throws Exception {
6307  3 testTypes("/** @param {string} opt_x\n@return {string} */\n" +
6308    "function f(opt_x) { if (!opt_x) { " +
6309    "throw new Error('x cannot be empty'); } return opt_x; }");
6310    }
6311   
 
6312  3 toggle public void testDfa12() throws Exception {
6313  3 testTypes("/** @param {string} x \n * @constructor \n */" +
6314    "var Bar = function(x) {};" +
6315    "/** @param {string} x */ function g(x) { return true; }" +
6316    "/** @param {string|number} opt_x */ " +
6317    "function f(opt_x) { " +
6318    " if (opt_x) { new Bar(g(opt_x) && 'x'); }" +
6319    "}",
6320    "actual parameter 1 of g does not match formal parameter\n" +
6321    "found : (number|string)\n" +
6322    "required: string");
6323    }
6324   
 
6325  3 toggle public void testDfa13() throws Exception {
6326  3 testTypes(
6327    "/**\n" +
6328    " * @param {string} x \n" +
6329    " * @param {number} y \n" +
6330    " * @param {number} z \n" +
6331    " */" +
6332    "function g(x, y, z) {}" +
6333    "function f() { " +
6334    " var x = 'a'; g(x, x = 3, x);" +
6335    "}");
6336    }
6337   
 
6338  3 toggle public void testTypeInferenceWithCast1() throws Exception {
6339  3 testTypes(
6340    "/**@return {(number,null,undefined)}*/function u(x) {return null;}" +
6341    "/**@param {number?} x\n@return {number?}*/function f(x) {return x;}" +
6342    "/**@return {number?}*/function g(x) {" +
6343    "var y = /**@type {number?}*/(u(x)); return f(y);}");
6344    }
6345   
 
6346  3 toggle public void testTypeInferenceWithCast2() throws Exception {
6347  3 testTypes(
6348    "/**@return {(number,null,undefined)}*/function u(x) {return null;}" +
6349    "/**@param {number?} x\n@return {number?}*/function f(x) {return x;}" +
6350    "/**@return {number?}*/function g(x) {" +
6351    "var y; y = /**@type {number?}*/(u(x)); return f(y);}");
6352    }
6353   
 
6354  3 toggle public void testTypeInferenceWithCast3() throws Exception {
6355  3 testTypes(
6356    "/**@return {(number,null,undefined)}*/function u(x) {return 1;}" +
6357    "/**@return {number}*/function g(x) {" +
6358    "return /**@type {number}*/(u(x));}");
6359    }
6360   
 
6361  3 toggle public void testTypeInferenceWithCast4() throws Exception {
6362  3 testTypes(
6363    "/**@return {(number,null,undefined)}*/function u(x) {return 1;}" +
6364    "/**@return {number}*/function g(x) {" +
6365    "return /**@type {number}*/(u(x)) && 1;}");
6366    }
6367   
 
6368  3 toggle public void testTypeInferenceWithCast5() throws Exception {
6369  3 testTypes(
6370    "/** @param {number} x */ function foo(x) {}" +
6371    "/** @param {{length:*}} y */ function bar(y) {" +
6372    " /** @type {string} */ y.length;" +
6373    " foo(y.length);" +
6374    "}",
6375    "actual parameter 1 of foo does not match formal parameter\n" +
6376    "found : string\n" +
6377    "required: number");
6378    }
6379   
 
6380  3 toggle public void testTypeInferenceWithClosure1() throws Exception {
6381  3 testTypes(
6382    "/** @return {boolean} */" +
6383    "function f() {" +
6384    " /** @type {?string} */ var x = null;" +
6385    " function g() { x = 'y'; } g(); " +
6386    " return x == null;" +
6387    "}");
6388    }
6389   
 
6390  3 toggle public void testTypeInferenceWithClosure2() throws Exception {
6391  3 testTypes(
6392    "/** @return {boolean} */" +
6393    "function f() {" +
6394    " /** @type {?string} */ var x = null;" +
6395    " function g() { x = 'y'; } g(); " +
6396    " return x === 3;" +
6397    "}",
6398    "condition always evaluates to false\n" +
6399    "left : (null|string|undefined)\n" +
6400    "right: number");
6401    }
6402   
 
6403  3 toggle public void testForwardPropertyReference() throws Exception {
6404  3 testTypes("/** @constructor */ var Foo = function() { this.init(); };" +
6405    "/** @return {string} */" +
6406    "Foo.prototype.getString = function() {" +
6407    " return this.number_;" +
6408    "};" +
6409    "Foo.prototype.init = function() {" +
6410    " /** @type {number} */" +
6411    " this.number_ = 3;" +
6412    "};",
6413    "inconsistent return type\n" +
6414    "found : number\n" +
6415    "required: string");
6416    }
6417   
 
6418  3 toggle public void testNoForwardTypeDeclaration() throws Exception {
6419  3 testTypes(
6420    "/** @param {MyType} x */ function f(x) {}",
6421    "Bad type annotation. Unknown type MyType");
6422    }
6423   
 
6424  3 toggle public void testNoForwardTypeDeclarationAndNoBraces() throws Exception {
6425  3 testTypes("/** @return The result. */ function f() {}");
6426    }
6427   
 
6428  3 toggle public void testForwardTypeDeclaration1() throws Exception {
6429  3 testClosureTypes(
6430    // malformed addDependency calls shouldn't cause a crash
6431    "goog.addDependency();" +
6432    "goog.addDependency('y', [goog]);" +
6433   
6434    "goog.addDependency('zzz.js', ['MyType'], []);" +
6435    "/** @param {MyType} x \n * @return {number} */" +
6436    "function f(x) { return 3; }", null);
6437    }
6438   
 
6439  3 toggle public void testForwardTypeDeclaration2() throws Exception {
6440  3 String f = "goog.addDependency('zzz.js', ['MyType'], []);" +
6441    "/** @param {MyType} x */ function f(x) { }";
6442  3 testClosureTypes(f, null);
6443  3 testClosureTypes(f + "f(3);",
6444    "actual parameter 1 of f does not match formal parameter\n" +
6445    "found : number\n" +
6446    "required: (MyType|null|undefined)");
6447    }
6448   
 
6449  3 toggle public void testForwardTypeDeclaration3() throws Exception {
6450  3 testClosureTypes(
6451    "goog.addDependency('zzz.js', ['MyType'], []);" +
6452    "/** @param {MyType} x */ function f(x) { return x; }" +
6453    "/** @constructor */ var MyType = function() {};" +
6454    "f(3);",
6455    "actual parameter 1 of f does not match formal parameter\n" +
6456    "found : number\n" +
6457    "required: (MyType|null|undefined)");
6458    }
6459   
 
6460  3 toggle public void testDuplicateTypeDef() throws Exception {
6461  3 testTypes(
6462    "var goog = {};" +
6463    "/** @constructor */ goog.Bar = function() {};" +
6464    "/** @typedef {number} */ goog.Bar;",
6465    "variable goog.Bar redefined with type None, " +
6466    "original definition at [testcode]:1 " +
6467    "with type function (new:goog.Bar): undefined");
6468    }
6469   
 
6470  3 toggle public void testTypeDef1() throws Exception {
6471  3 testTypes(
6472    "var goog = {};" +
6473    "/** @typedef {number} */ goog.Bar;" +
6474    "/** @param {goog.Bar} x */ function f(x) {}" +
6475    "f(3);");
6476    }
6477   
 
6478  3 toggle public void testTypeDef2() throws Exception {
6479  3 testTypes(
6480    "var goog = {};" +
6481    "/** @typedef {number} */ goog.Bar;" +
6482    "/** @param {goog.Bar} x */ function f(x) {}" +
6483    "f('3');",
6484    "actual parameter 1 of f does not match formal parameter\n" +
6485    "found : string\n" +
6486    "required: number");
6487    }
6488   
 
6489  3 toggle public void testTypeDef3() throws Exception {
6490  3 testTypes(
6491    "var goog = {};" +
6492    "/** @typedef {number} */ var Bar;" +
6493    "/** @param {Bar} x */ function f(x) {}" +
6494    "f('3');",
6495    "actual parameter 1 of f does not match formal parameter\n" +
6496    "found : string\n" +
6497    "required: number");
6498    }
6499   
 
6500  3 toggle public void testCircularTypeDef() throws Exception {
6501  3 testTypes(
6502    "var goog = {};" +
6503    "/** @typedef {number|Array.<goog.Bar>} */ goog.Bar;" +
6504    "/** @param {goog.Bar} x */ function f(x) {}" +
6505    "f(3); f([3]); f([[3]]);");
6506    }
6507   
 
6508  3 toggle public void testGetTypedPercent1() throws Exception {
6509  3 String js = "var id = function(x) { return x; }\n" +
6510    "var id2 = function(x) { return id(x); }";
6511  3 assertEquals(50.0, getTypedPercent(js), 0.1);
6512    }
6513   
 
6514  3 toggle public void testGetTypedPercent2() throws Exception {
6515  3 String js = "var x = {}; x.y = 1;";
6516  3 assertEquals(100.0, getTypedPercent(js), 0.1);
6517    }
6518   
 
6519  3 toggle public void testGetTypedPercent3() throws Exception {
6520  3 String js = "var f = function(x) { x.a = x.b; }";
6521  3 assertEquals(50.0, getTypedPercent(js), 0.1);
6522    }
6523   
 
6524  3 toggle public void testGetTypedPercent4() throws Exception {
6525  3 String js = "var n = {};\n /** @constructor */ n.T = function() {};\n" +
6526    "/** @type n.T */ var x = new n.T();";
6527  3 assertEquals(100.0, getTypedPercent(js), 0.1);
6528    }
6529   
 
6530  15 toggle private double getTypedPercent(String js) throws Exception {
6531  15 Node n = compiler.parseTestCode(js);
6532   
6533  15 Node externs = new Node(Token.BLOCK);
6534  15 Node externAndJsRoot = new Node(Token.BLOCK, externs, n);
6535  15 externAndJsRoot.setIsSyntheticBlock(true);
6536   
6537  15 TypeCheck t = makeTypeCheck();
6538  15 t.processForTesting(null, n);
6539  15 return t.getTypedPercent();
6540    }
6541   
 
6542  12 toggle private ObjectType getInstanceType(Node js1Node) {
6543  12 JSType type = js1Node.getFirstChild().getJSType();
6544  12 assertNotNull(type);
6545  12 assertTrue(type instanceof FunctionType);
6546  12 FunctionType functionType = (FunctionType) type;
6547  12 assertTrue(functionType.isConstructor());
6548  12 return functionType.getInstanceType();
6549    }
6550   
 
6551  3 toggle public void testPrototypePropertyReference() throws Exception {
6552  3 TypeCheckResult p = parseAndTypeCheckWithScope(""
6553    + "/** @constructor */\n"
6554    + "function Foo() {}\n"
6555    + "/** @param {number} a */\n"
6556    + "Foo.prototype.bar = function(a){};\n"
6557    + "/** @param {Foo} f */\n"
6558    + "function baz(f) {\n"
6559    + " Foo.prototype.bar.call(f, 3);\n"
6560    + "}");
6561  3 assertEquals(0, compiler.getErrorCount());
6562  3 assertEquals(0, compiler.getWarningCount());
6563   
6564  3 assertTrue(p.scope.getVar("Foo").getType() instanceof FunctionType);
6565  3 FunctionType fooType = (FunctionType) p.scope.getVar("Foo").getType();
6566  3 assertEquals("function (this:Foo, number): undefined",
6567    fooType.getPrototype().getPropertyType("bar").toString());
6568    }
6569   
 
6570  3 toggle public void testResolvingNamedTypes() throws Exception {
6571  3 String js = ""
6572    + "/** @constructor */\n"
6573    + "var Foo = function() {}\n"
6574    + "/** @param {number} a */\n"
6575    + "Foo.prototype.foo = function(a) {\n"
6576    + " return this.baz().toString();\n"
6577    + "};\n"
6578    + "/** @return {Baz} */\n"
6579    + "Foo.prototype.baz = function() { return new Baz(); };\n"
6580    + "/** @constructor\n"
6581    + " * @extends Foo */\n"
6582    + "var Bar = function() {};"
6583    + "/** @constructor */\n"
6584    + "var Baz = function() {};";
6585  3 assertEquals(100.0, getTypedPercent(js), 0.1);
6586    }
6587   
 
6588  3 toggle public void testMissingProperty1() throws Exception {
6589  3 testTypes(
6590    "/** @constructor */ function Foo() {}" +
6591    "Foo.prototype.bar = function() { return this.a; };" +
6592    "Foo.prototype.baz = function() { this.a = 3; };");
6593    }
6594   
 
6595  3 toggle public void testMissingProperty2() throws Exception {
6596  3 testTypes(
6597    "/** @constructor */ function Foo() {}" +
6598    "Foo.prototype.bar = function() { return this.a; };" +
6599    "Foo.prototype.baz = function() { this.b = 3; };",
6600    "Property a never defined on Foo");
6601    }
6602   
 
6603  3 toggle public void testMissingProperty3() throws Exception {
6604  3 testTypes(
6605    "/** @constructor */ function Foo() {}" +
6606    "Foo.prototype.bar = function() { return this.a; };" +
6607    "(new Foo).a = 3;");
6608    }
6609   
 
6610  3 toggle public void testMissingProperty4() throws Exception {
6611  3 testTypes(
6612    "/** @constructor */ function Foo() {}" +
6613    "Foo.prototype.bar = function() { return this.a; };" +
6614    "(new Foo).b = 3;",
6615    "Property a never defined on Foo");
6616    }
6617   
 
6618  3 toggle public void testMissingProperty5() throws Exception {
6619  3 testTypes(
6620    "/** @constructor */ function Foo() {}" +
6621    "Foo.prototype.bar = function() { return this.a; };" +
6622    "/** @constructor */ function Bar() { this.a = 3; };",
6623    "Property a never defined on Foo");
6624    }
6625   
 
6626  3 toggle public void testMissingProperty6() throws Exception {
6627  3 testTypes(
6628    "/** @constructor */ function Foo() {}" +
6629    "Foo.prototype.bar = function() { return this.a; };" +
6630    "/** @constructor \n * @extends {Foo} */ " +
6631    "function Bar() { this.a = 3; };");
6632    }
6633   
 
6634  3 toggle public void testMissingProperty7() throws Exception {
6635  3 testTypes(
6636    "/** @param {Object} obj */" +
6637    "function foo(obj) { return obj.impossible; }",
6638    "Property impossible never defined on Object");
6639    }
6640   
 
6641  3 toggle public void testMissingProperty8() throws Exception {
6642  3 testTypes(
6643    "/** @param {Object} obj */" +
6644    "function foo(obj) { return typeof obj.impossible; }");
6645    }
6646   
 
6647  3 toggle public void testMissingProperty9() throws Exception {
6648  3 testTypes(
6649    "/** @param {Object} obj */" +
6650    "function foo(obj) { if (obj.impossible) { return true; } }");
6651    }
6652   
 
6653  3 toggle public void testMissingProperty10() throws Exception {
6654  3 testTypes(
6655    "/** @param {Object} obj */" +
6656    "function foo(obj) { while (obj.impossible) { return true; } }");
6657    }
6658   
 
6659  3 toggle public void testMissingProperty11() throws Exception {
6660  3 testTypes(
6661    "/** @param {Object} obj */" +
6662    "function foo(obj) { for (;obj.impossible;) { return true; } }");
6663    }
6664   
 
6665  3 toggle public void testMissingProperty12() throws Exception {
6666  3 testTypes(
6667    "/** @param {Object} obj */" +
6668    "function foo(obj) { do { } while (obj.impossible); }");
6669    }
6670   
 
6671  3 toggle public void testMissingProperty13() throws Exception {
6672  3 testTypes(
6673    "var goog = {}; goog.isDef = function(x) { return false; };" +
6674    "/** @param {Object} obj */" +
6675    "function foo(obj) { return goog.isDef(obj.impossible); }");
6676    }
6677   
 
6678  3 toggle public void testMissingProperty14() throws Exception {
6679  3 testTypes(
6680    "var goog = {}; goog.isDef = function(x) { return false; };" +
6681    "/** @param {Object} obj */" +
6682    "function foo(obj) { return goog.isNull(obj.impossible); }",
6683    "Property isNull never defined on goog");
6684    }
6685   
 
6686  3 toggle public void testMissingProperty15() throws Exception {
6687  3 testTypes(
6688    "/** @param {Object} x */" +
6689    "function f(x) { if (x.foo) { x.foo(); } }");
6690    }
6691   
 
6692  3 toggle public void testMissingProperty16() throws Exception {
6693  3 testTypes(
6694    "/** @param {Object} x */" +
6695    "function f(x) { x.foo(); if (x.foo) {} }",
6696    "Property foo never defined on Object");
6697    }
6698   
 
6699  3 toggle public void testMissingProperty17() throws Exception {
6700  3 testTypes(
6701    "/** @param {Object} x */" +
6702    "function f(x) { if (typeof x.foo == 'function') { x.foo(); } }");
6703    }
6704   
 
6705  3 toggle public void testMissingProperty18() throws Exception {
6706  3 testTypes(
6707    "/** @param {Object} x */" +
6708    "function f(x) { if (x.foo instanceof Function) { x.foo(); } }");
6709    }
6710   
 
6711  3 toggle public void testMissingProperty19() throws Exception {
6712  3 testTypes(
6713    "/** @param {Object} x */" +
6714    "function f(x) { if (x.bar) { if (x.foo) {} } else { x.foo(); } }",
6715    "Property foo never defined on Object");
6716    }
6717   
 
6718  3 toggle public void testMissingProperty21() throws Exception {
6719  3 testTypes(
6720    "/** @param {Object} x */" +
6721    "function f(x) { x.foo && x.foo(); }");
6722    }
6723   
 
6724  3 toggle public void testMissingProperty22() throws Exception {
6725  3 testTypes(
6726    "/** @param {Object} x \n * @return {boolean} */" +
6727    "function f(x) { return x.foo ? x.foo() : true; }");
6728    }
6729   
 
6730  3 toggle public void testMissingProperty23() throws Exception {
6731  3 testTypes(
6732    "function f(x) { x.impossible(); }",
6733    "Property impossible never defined on x");
6734    }
6735   
 
6736  3 toggle public void testMissingProperty24() throws Exception {
6737  3 testClosureTypes(
6738    "goog.addDependency('zzz.js', ['MissingType'], []);" +
6739    "/** @param {MissingType} x */" +
6740    "function f(x) { x.impossible(); }", null);
6741    }
6742   
 
6743  3 toggle public void testMissingProperty25() throws Exception {
6744  3 testTypes(
6745    "/** @constructor */ var Foo = function() {};" +
6746    "Foo.prototype.bar = function() {};" +
6747    "/** @constructor */ var FooAlias = Foo;" +
6748    "(new FooAlias()).bar();");
6749    }
6750   
 
6751  3 toggle public void testMissingProperty26() throws Exception {
6752  3 testTypes(
6753    "/** @constructor */ var Foo = function() {};" +
6754    "/** @constructor */ var FooAlias = Foo;" +
6755    "FooAlias.prototype.bar = function() {};" +
6756    "(new Foo()).bar();");
6757    }
6758   
 
6759  3 toggle public void testMissingProperty27() throws Exception {
6760  3 testClosureTypes(
6761    "goog.addDependency('zzz.js', ['MissingType'], []);" +
6762    "/** @param {?MissingType} x */" +
6763    "function f(x) {" +
6764    " for (var parent = x; parent; parent = parent.getParent()) {}" +
6765    "}", null);
6766    }
6767   
 
6768  3 toggle public void testMissingProperty28() throws Exception {
6769  3 testTypes(
6770    "function f(obj) {" +
6771    " /** @type {*} */ obj.foo;" +
6772    " return obj.foo;" +
6773    "}");
6774  3 testTypes(
6775    "function f(obj) {" +
6776    " /** @type {*} */ obj.foo;" +
6777    " return obj.foox;" +
6778    "}",
6779    "Property foox never defined on obj");
6780    }
6781   
 
6782  3 toggle public void testMissingProperty29() throws Exception {
6783    // This used to emit a warning.
6784  3 testTypes(
6785    // externs
6786    "/** @constructor */ var Foo;" +
6787    "Foo.prototype.opera;" +
6788    "Foo.prototype.opera.postError;",
6789    "",
6790    null,
6791    false);
6792    }
6793   
 
6794  3 toggle public void testDeclaredNativeTypeEquality() throws Exception {
6795  3 Node n = parseAndTypeCheck("/** @constructor */ function Object() {};");
6796  3 assertEquals(registry.getNativeType(JSTypeNative.OBJECT_FUNCTION_TYPE),
6797    n.getFirstChild().getJSType());
6798    }
6799   
 
6800  3 toggle public void testUndefinedVar() throws Exception {
6801  3 Node n = parseAndTypeCheck("var undefined;");
6802  3 assertEquals(registry.getNativeType(JSTypeNative.VOID_TYPE),
6803    n.getFirstChild().getFirstChild().getJSType());
6804    }
6805   
 
6806  3 toggle public void testFlowScopeBug1() throws Exception {
6807  3 Node n = parseAndTypeCheck("/** @param {number} a \n"
6808    + "* @param {number} b */\n"
6809    + "function f(a, b) {\n"
6810    + "/** @type number */"
6811    + "var i = 0;"
6812    + "for (; (i + a) < b; ++i) {}}");
6813   
6814    // check the type of the add node for i + f
6815  3 assertEquals(registry.getNativeType(JSTypeNative.NUMBER_TYPE),
6816    n.getFirstChild().getLastChild().getLastChild().getFirstChild()
6817    .getNext().getFirstChild().getJSType());
6818    }
6819   
 
6820  3 toggle public void testFlowScopeBug2() throws Exception {
6821  3 Node n = parseAndTypeCheck("/** @constructor */ function Foo() {};\n"
6822    + "Foo.prototype.hi = false;"
6823    + "function foo(a, b) {\n"
6824    + " /** @type Array */"
6825    + " var arr;"
6826    + " /** @type number */"
6827    + " var iter;"
6828    + " for (iter = 0; iter < arr.length; ++ iter) {"
6829    + " /** @type Foo */"
6830    + " var afoo = arr[iter];"
6831    + " afoo;"
6832    + " }"
6833    + "}");
6834   
6835    // check the type of afoo when referenced
6836  3 assertTypeEquals(registry.createOptionalType(
6837    registry.createNullableType(registry.getType("Foo"))),
6838    n.getLastChild().getLastChild().getLastChild().getLastChild()
6839    .getLastChild().getLastChild().getJSType());
6840    }
6841   
 
6842  3 toggle public void testAddSingletonGetter() {
6843  3 Node n = parseAndTypeCheck(
6844    "/** @constructor */ function Foo() {};\n" +
6845    "goog.addSingletonGetter(Foo);");
6846  3 ObjectType o = (ObjectType) n.getFirstChild().getJSType();
6847  3 assertEquals("function (): Foo",
6848    o.getPropertyType("getInstance").toString());
6849  3 assertEquals("Foo", o.getPropertyType("instance_").toString());
6850    }
6851   
 
6852  3 toggle public void testTypeCheckStandaloneAST() throws Exception {
6853  3 Node n = compiler.parseTestCode("function Foo() { }");
6854  3 typeCheck(n);
6855  3 MemoizedScopeCreator scopeCreator =
6856    new MemoizedScopeCreator(new TypedScopeCreator(compiler));
6857  3 Scope topScope = scopeCreator.createScope(n, null);
6858   
6859  3 Node second = compiler.parseTestCode("new Foo");
6860   
6861  3 Node externs = new Node(Token.BLOCK);
6862  3 Node externAndJsRoot = new Node(Token.BLOCK, externs, second);
6863  3 externAndJsRoot.setIsSyntheticBlock(true);
6864   
6865  3 new TypeCheck(
6866    compiler,
6867    new SemanticReverseAbstractInterpreter(
6868    compiler.getCodingConvention(), registry),
6869    registry, topScope, scopeCreator, CheckLevel.WARNING, CheckLevel.OFF)
6870    .process(null, second);
6871   
6872  3 assertEquals(1, compiler.getWarningCount());
6873  3 assertEquals("cannot instantiate non-constructor",
6874    compiler.getWarnings()[0].description);
6875    }
6876   
 
6877  42 toggle private void checkObjectType(ObjectType objectType, String propertyName,
6878    JSType expectedType) {
6879  42 assertTrue("Expected " + objectType.getReferenceName() +
6880    " to have property " +
6881    propertyName, objectType.hasProperty(propertyName));
6882  42 assertTypeEquals("Expected " + objectType.getReferenceName() +
6883    "'s property " +
6884    propertyName + " to have type " + expectedType,
6885    expectedType, objectType.getPropertyType(propertyName));
6886    }
6887   
 
6888  975 toggle private void testTypes(String js) throws Exception {
6889  975 testTypes(js, (String) null);
6890    }
6891   
 
6892  2031 toggle private void testTypes(String js, String description) throws Exception {
6893  2031 testTypes(js, description, false);
6894    }
6895   
 
6896  12 toggle private void testTypes(String js, DiagnosticType type) throws Exception {
6897  12 testTypes(js, type.format(), false);
6898    }
6899   
 
6900  75 toggle private void testClosureTypes(String js, String description)
6901    throws Exception {
6902  75 testClosureTypesMultipleWarnings(js,
6903  75 description == null ? null : Lists.newArrayList(description));
6904    }
6905   
 
6906  99 toggle private void testClosureTypesMultipleWarnings(
6907    String js, List<String> descriptions) throws Exception {
6908  99 Node n = compiler.parseTestCode(js);
6909  99 Node externs = new Node(Token.BLOCK);
6910  99 Node externAndJsRoot = new Node(Token.BLOCK, externs, n);
6911  99 externAndJsRoot.setIsSyntheticBlock(true);
6912   
6913  99 assertEquals("parsing error: " +
6914    Joiner.on(", ").join(compiler.getErrors()),
6915    0, compiler.getErrorCount());
6916   
6917    // For processing goog.addDependency for forward typedefs.
6918  99 new ProcessClosurePrimitives(compiler, null, CheckLevel.ERROR)
6919    .process(null, n);
6920   
6921  99 CodingConvention convention = compiler.getCodingConvention();
6922  99 new TypeCheck(compiler,
6923    new ClosureReverseAbstractInterpreter(
6924    convention, registry).append(
6925    new SemanticReverseAbstractInterpreter(
6926    convention, registry))
6927    .getFirst(),
6928    registry)
6929    .processForTesting(null, n);
6930   
6931  99 assertEquals(0, compiler.getErrorCount());
6932   
6933  99 if (descriptions == null) {
6934  57 assertEquals(
6935    "unexpected warning(s) : " +
6936    Joiner.on(", ").join(compiler.getWarnings()),
6937    0, compiler.getWarningCount());
6938    } else {
6939  42 assertEquals(descriptions.size(), compiler.getWarningCount());
6940  42 Set<String> actualWarningDescriptions = Sets.newHashSet();
6941  108 for (int i = 0; i < descriptions.size(); i++) {
6942  66 actualWarningDescriptions.add(compiler.getWarnings()[i].description);
6943    }
6944  42 assertEquals(
6945    Sets.newHashSet(descriptions), actualWarningDescriptions);
6946    }
6947    }
6948   
 
6949  2049 toggle void testTypes(String js, String description, boolean isError)
6950    throws Exception {
6951  2049 testTypes(DEFAULT_EXTERNS, js, description, isError);
6952    }
6953   
 
6954  2067 toggle void testTypes(String externs, String js, String description, boolean isError)
6955    throws Exception {
6956  2067 Node n = parseAndTypeCheck(externs, js);
6957   
6958  2067 JSError[] errors = compiler.getErrors();
6959  2067 if (description != null && isError) {
6960  0 assertTrue("expected an error", errors.length > 0);
6961  0 assertEquals(description, errors[0].description);
6962  0 errors = Arrays.asList(errors).subList(1, errors.length).toArray(
6963    new JSError[errors.length - 1]);
6964    }
6965  2067 if (errors.length > 0) {
6966  0 fail("unexpected error(s):\n" + Joiner.on("\n").join(errors));
6967    }
6968   
6969  2067 JSError[] warnings = compiler.getWarnings();
6970  2067 if (description != null && !isError) {
6971  1080 assertTrue("expected a warning", warnings.length > 0);
6972  1080 assertEquals(description, warnings[0].description);
6973  1080 warnings = Arrays.asList(warnings).subList(1, warnings.length).toArray(
6974    new JSError[warnings.length - 1]);
6975    }
6976  2067 if (warnings.length > 0) {
6977  0 fail("unexpected warnings(s):\n" + Joiner.on("\n").join(warnings));
6978    }
6979    }
6980   
6981    /**
6982    * Parses and type checks the JavaScript code.
6983    */
 
6984  84 toggle private Node parseAndTypeCheck(String js) {
6985  84 return parseAndTypeCheck(DEFAULT_EXTERNS, js);
6986    }
6987   
 
6988  2151 toggle private Node parseAndTypeCheck(String externs, String js) {
6989  2151 return parseAndTypeCheckWithScope(externs, js).root;
6990    }
6991   
6992    /**
6993    * Parses and type checks the JavaScript code and returns the Scope used
6994    * whilst type checking.
6995    */
 
6996  48 toggle private TypeCheckResult parseAndTypeCheckWithScope(String js) {
6997  48 return parseAndTypeCheckWithScope(DEFAULT_EXTERNS, js);
6998    }
6999   
 
7000  2199 toggle private TypeCheckResult parseAndTypeCheckWithScope(
7001    String externs, String js) {
7002  2199 compiler.init(
7003    Lists.newArrayList(SourceFile.fromCode("[externs]", externs)),
7004    Lists.newArrayList(SourceFile.fromCode("[testcode]", js)),
7005    compiler.getOptions());
7006   
7007  2199 Node n = compiler.getInput(new InputId("[testcode]")).getAstRoot(compiler);
7008  2199 Node externsNode = compiler.getInput(new InputId("[externs]"))
7009    .getAstRoot(compiler);
7010  2199 Node externAndJsRoot = new Node(Token.BLOCK, externsNode, n);
7011  2199 externAndJsRoot.setIsSyntheticBlock(true);
7012   
7013  2199 assertEquals("parsing error: " +
7014    Joiner.on(", ").join(compiler.getErrors()),
7015    0, compiler.getErrorCount());
7016   
7017  2199 Scope s = makeTypeCheck().processForTesting(externsNode, n);
7018  2199 return new TypeCheckResult(n, s);
7019    }
7020   
 
7021  18 toggle private Node typeCheck(Node n) {
7022  18 Node externsNode = new Node(Token.BLOCK);
7023  18 Node externAndJsRoot = new Node(Token.BLOCK, externsNode, n);
7024  18 externAndJsRoot.setIsSyntheticBlock(true);
7025   
7026  18 makeTypeCheck().processForTesting(null, n);
7027  18 return n;
7028    }
7029   
 
7030  2256 toggle private TypeCheck makeTypeCheck() {
7031  2256 return new TypeCheck(
7032    compiler,
7033    new SemanticReverseAbstractInterpreter(
7034    compiler.getCodingConvention(), registry),
7035    registry);
7036    }
7037   
 
7038  9 toggle void testTypes(String js, String[] warnings) throws Exception {
7039  9 Node n = compiler.parseTestCode(js);
7040  9 assertEquals(0, compiler.getErrorCount());
7041  9 Node externsNode = new Node(Token.BLOCK);
7042  9 Node externAndJsRoot = new Node(Token.BLOCK, externsNode, n);
7043   
7044  9 makeTypeCheck().processForTesting(null, n);
7045  9 assertEquals(0, compiler.getErrorCount());
7046  9 if (warnings != null) {
7047  9 assertEquals(warnings.length, compiler.getWarningCount());
7048  9 JSError[] messages = compiler.getWarnings();
7049  27 for (int i = 0; i < warnings.length && i < compiler.getWarningCount();
7050    i++) {
7051  18 assertEquals(warnings[i], messages[i].description);
7052    }
7053    } else {
7054  0 assertEquals(0, compiler.getWarningCount());
7055    }
7056    }
7057   
 
7058  9 toggle String suppressMissingProperty(String ... props) {
7059  9 String result = "function dummy(x) { ";
7060  9 for (String prop : props) {
7061  15 result += "x." + prop + " = 3;";
7062    }
7063  9 return result + "}";
7064    }
7065   
 
7066    private static class TypeCheckResult {
7067    private final Node root;
7068    private final Scope scope;
7069   
 
7070  2199 toggle private TypeCheckResult(Node root, Scope scope) {
7071  2199 this.root = root;
7072  2199 this.scope = scope;
7073    }
7074    }
7075    }